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
39 #include "sim/syscall_emul.hh"
40 #include "base/chunk_generator.hh"
41 #include "base/trace.hh"
42 #include "cpu/thread_context.hh"
43 #include "cpu/base.hh"
44 #include "mem/page_table.hh"
45 #include "sim/process.hh"
47 #include "sim/sim_exit.hh"
50 using namespace TheISA
;
53 SyscallDesc::doSyscall(int callnum
, Process
*process
, ThreadContext
*tc
)
55 DPRINTFR(SyscallVerbose
, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
56 curTick
,tc
->getCpuPtr()->name(), name
,
57 tc
->getSyscallArg(0),tc
->getSyscallArg(1),
58 tc
->getSyscallArg(2),tc
->getSyscallArg(3));
60 SyscallReturn retval
= (*funcPtr
)(this, callnum
, process
, tc
);
62 DPRINTFR(SyscallVerbose
, "%d: %s: syscall %s returns %d\n",
63 curTick
,tc
->getCpuPtr()->name(), name
, retval
.value());
65 if (!(flags
& SyscallDesc::SuppressReturnValue
))
66 tc
->setSyscallReturn(retval
);
71 unimplementedFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
74 fatal("syscall %s (#%d) unimplemented.", desc
->name
, callnum
);
81 ignoreFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
84 warn("ignoring syscall %s(%d, %d, ...)", desc
->name
,
85 tc
->getSyscallArg(0), tc
->getSyscallArg(1));
92 exitFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
95 exitSimLoop("target called exit()", tc
->getSyscallArg(0) & 0xff);
102 getpagesizeFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
104 return (int)VMPageSize
;
109 obreakFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
113 // change brk addr to first arg
114 Addr new_brk
= tc
->getSyscallArg(0);
116 for (ChunkGenerator
gen(p
->brk_point
, new_brk
- p
->brk_point
,
117 VMPageSize
); !gen
.done(); gen
.next()) {
118 if (!p
->pTable
->translate(gen
.addr(), junk
))
119 p
->pTable
->allocate(roundDown(gen
.addr(), VMPageSize
),
122 p
->brk_point
= new_brk
;
124 DPRINTF(SyscallVerbose
, "Break Point changed to: %#X\n", p
->brk_point
);
130 closeFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
132 int target_fd
= tc
->getSyscallArg(0);
133 int status
= close(p
->sim_fd(target_fd
));
135 p
->free_fd(target_fd
);
141 readFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
143 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
144 int nbytes
= tc
->getSyscallArg(2);
145 BufferArg
bufArg(tc
->getSyscallArg(1), nbytes
);
147 int bytes_read
= read(fd
, bufArg
.bufferPtr(), nbytes
);
149 if (bytes_read
!= -1)
150 bufArg
.copyOut(tc
->getMemPort());
156 writeFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
158 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
159 int nbytes
= tc
->getSyscallArg(2);
160 BufferArg
bufArg(tc
->getSyscallArg(1), nbytes
);
162 bufArg
.copyIn(tc
->getMemPort());
164 int bytes_written
= write(fd
, bufArg
.bufferPtr(), nbytes
);
168 return bytes_written
;
173 lseekFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
175 int fd
= p
->sim_fd(tc
->getSyscallArg(0));
176 uint64_t offs
= tc
->getSyscallArg(1);
177 int whence
= tc
->getSyscallArg(2);
179 off_t result
= lseek(fd
, offs
, whence
);
181 return (result
== (off_t
)-1) ? -errno
: result
;
186 munmapFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
188 // given that we don't really implement mmap, munmap is really easy
193 const char *hostname
= "m5.eecs.umich.edu";
196 gethostnameFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
198 int name_len
= tc
->getSyscallArg(1);
199 BufferArg
name(tc
->getSyscallArg(0), name_len
);
201 strncpy((char *)name
.bufferPtr(), hostname
, name_len
);
203 name
.copyOut(tc
->getMemPort());
209 unlinkFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
213 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
214 return (TheISA::IntReg
)-EFAULT
;
216 int result
= unlink(path
.c_str());
217 return (result
== -1) ? -errno
: result
;
221 renameFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
225 if (!tc
->getMemPort()->tryReadString(old_name
, tc
->getSyscallArg(0)))
230 if (!tc
->getMemPort()->tryReadString(new_name
, tc
->getSyscallArg(1)))
233 int64_t result
= rename(old_name
.c_str(), new_name
.c_str());
234 return (result
== -1) ? -errno
: result
;
238 truncateFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
242 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
245 off_t length
= tc
->getSyscallArg(1);
247 int result
= truncate(path
.c_str(), length
);
248 return (result
== -1) ? -errno
: result
;
252 ftruncateFunc(SyscallDesc
*desc
, int num
, Process
*process
, ThreadContext
*tc
)
254 int fd
= process
->sim_fd(tc
->getSyscallArg(0));
259 off_t length
= tc
->getSyscallArg(1);
261 int result
= ftruncate(fd
, length
);
262 return (result
== -1) ? -errno
: result
;
266 chownFunc(SyscallDesc
*desc
, int num
, Process
*p
, ThreadContext
*tc
)
270 if (!tc
->getMemPort()->tryReadString(path
, tc
->getSyscallArg(0)))
274 uint32_t owner
= tc
->getSyscallArg(1);
275 uid_t hostOwner
= owner
;
276 uint32_t group
= tc
->getSyscallArg(2);
277 gid_t hostGroup
= group
;
279 int result
= chown(path
.c_str(), hostOwner
, hostGroup
);
280 return (result
== -1) ? -errno
: result
;
284 fchownFunc(SyscallDesc
*desc
, int num
, Process
*process
, ThreadContext
*tc
)
286 int fd
= process
->sim_fd(tc
->getSyscallArg(0));
292 uint32_t owner
= tc
->getSyscallArg(1);
293 uid_t hostOwner
= owner
;
294 uint32_t group
= tc
->getSyscallArg(2);
295 gid_t hostGroup
= group
;
297 int result
= fchown(fd
, hostOwner
, hostGroup
);
298 return (result
== -1) ? -errno
: result
;
303 fcntlFunc(SyscallDesc
*desc
, int num
, Process
*process
,
306 int fd
= tc
->getSyscallArg(0);
308 if (fd
< 0 || process
->sim_fd(fd
) < 0)
311 int cmd
= tc
->getSyscallArg(1);
314 // if we really wanted to support this, we'd need to do it
315 // in the target fd space.
316 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd
);
319 case 1: // F_GETFD (get close-on-exec flag)
320 case 2: // F_SETFD (set close-on-exec flag)
323 case 3: // F_GETFL (get file flags)
324 case 4: // F_SETFL (set file flags)
325 // not sure if this is totally valid, but we'll pass it through
326 // to the underlying OS
327 warn("fcntl(%d, %d) passed through to host\n", fd
, cmd
);
328 return fcntl(process
->sim_fd(fd
), cmd
);
331 case 7: // F_GETLK (get lock)
332 case 8: // F_SETLK (set lock)
333 case 9: // F_SETLKW (set lock and wait)
334 // don't mess with file locking... just act like it's OK
335 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd
, cmd
);
339 warn("Unknown fcntl command %d\n", cmd
);
345 fcntl64Func(SyscallDesc
*desc
, int num
, Process
*process
,
348 int fd
= tc
->getSyscallArg(0);
350 if (fd
< 0 || process
->sim_fd(fd
) < 0)
353 int cmd
= tc
->getSyscallArg(1);
356 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd
);
359 case 34: // F_SETLK64
360 case 35: // F_SETLKW64
361 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd
);
365 // not sure if this is totally valid, but we'll pass it through
366 // to the underlying OS
367 warn("fcntl64(%d, %d) passed through to host\n", fd
, cmd
);
368 return fcntl(process
->sim_fd(fd
), cmd
);
374 pipePseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
377 int fds
[2], sim_fds
[2];
378 int pipe_retval
= pipe(fds
);
380 if (pipe_retval
< 0) {
385 sim_fds
[0] = process
->alloc_fd(fds
[0]);
386 sim_fds
[1] = process
->alloc_fd(fds
[1]);
388 // Alpha Linux convention for pipe() is that fd[0] is returned as
389 // the return value of the function, and fd[1] is returned in r20.
390 tc
->setIntReg(SyscallPseudoReturnReg
, sim_fds
[1]);
396 getpidPseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
399 // Make up a PID. There's no interprocess communication in
400 // fake_syscall mode, so there's no way for a process to know it's
401 // not getting a unique value.
403 tc
->setIntReg(SyscallPseudoReturnReg
, 99);
409 getuidPseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
412 // Make up a UID and EUID... it shouldn't matter, and we want the
413 // simulation to be deterministic.
416 tc
->setIntReg(SyscallPseudoReturnReg
, 100); //EUID
422 getgidPseudoFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
425 // Get current group ID. EGID goes in r20.
426 tc
->setIntReg(SyscallPseudoReturnReg
, 100); //EGID
432 setuidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
435 // can't fathom why a benchmark would call this.
436 warn("Ignoring call to setuid(%d)\n", tc
->getSyscallArg(0));
441 getpidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
444 // Make up a PID. There's no interprocess communication in
445 // fake_syscall mode, so there's no way for a process to know it's
446 // not getting a unique value.
448 tc
->setIntReg(SyscallPseudoReturnReg
, 99); //PID
453 getppidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
460 getuidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
467 geteuidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
474 getgidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,
481 getegidFunc(SyscallDesc
*desc
, int callnum
, Process
*process
,