Deleted Added
sdiff udiff text old ( 5543:3af77710f397 ) new ( 5748:f28f020f3006 )
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 <fcntl.h>
33#include <unistd.h>
34
35#include <string>
36#include <iostream>
37
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"
45
46#include "sim/sim_exit.hh"
47
48using namespace std;
49using namespace TheISA;
50
51void
52SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
53{
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));
58
59 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
60
61 DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
62 curTick,tc->getCpuPtr()->name(), name, retval.value());
63
64 if (!(flags & SyscallDesc::SuppressReturnValue))
65 tc->setSyscallReturn(retval);
66}
67
68
69SyscallReturn
70unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
71 ThreadContext *tc)
72{
73 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
74
75 return 1;
76}
77
78
79SyscallReturn
80ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
81 ThreadContext *tc)
82{
83 warn("ignoring syscall %s(%d, %d, ...)", desc->name,
84 tc->getSyscallArg(0), tc->getSyscallArg(1));
85
86 return 0;
87}
88
89
90SyscallReturn
91exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
92 ThreadContext *tc)
93{
94 if (tc->exit()) {
95 exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff);
96 }
97
98 return 1;
99}
100
101
102SyscallReturn
103getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
104{
105 return (int)VMPageSize;
106}
107
108
109SyscallReturn
110brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
111{
112 // change brk addr to first arg
113 Addr new_brk = tc->getSyscallArg(0);
114
115 // in Linux at least, brk(0) returns the current break value
116 // (note that the syscall and the glibc function have different behavior)
117 if (new_brk == 0)
118 return p->brk_point;
119
120 if (new_brk > p->brk_point) {
121 // might need to allocate some new pages
122 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
123 VMPageSize); !gen.done(); gen.next()) {
124 if (!p->pTable->translate(gen.addr()))
125 p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
126 VMPageSize);
127 }
128 }
129
130 p->brk_point = new_brk;
131 DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
132 return p->brk_point;
133}
134
135
136SyscallReturn
137closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
138{
139 int target_fd = tc->getSyscallArg(0);
140 int status = close(p->sim_fd(target_fd));
141 if (status >= 0)
142 p->free_fd(target_fd);
143 return status;
144}
145
146
147SyscallReturn
148readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
149{
150 int fd = p->sim_fd(tc->getSyscallArg(0));
151 int nbytes = tc->getSyscallArg(2);
152 BufferArg bufArg(tc->getSyscallArg(1), nbytes);
153
154 int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
155
156 if (bytes_read != -1)
157 bufArg.copyOut(tc->getMemPort());
158
159 return bytes_read;
160}
161
162SyscallReturn
163writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
164{
165 int fd = p->sim_fd(tc->getSyscallArg(0));
166 int nbytes = tc->getSyscallArg(2);
167 BufferArg bufArg(tc->getSyscallArg(1), nbytes);
168
169 bufArg.copyIn(tc->getMemPort());
170
171 int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
172
173 fsync(fd);
174
175 return bytes_written;
176}
177
178
179SyscallReturn
180lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
181{
182 int fd = p->sim_fd(tc->getSyscallArg(0));
183 uint64_t offs = tc->getSyscallArg(1);
184 int whence = tc->getSyscallArg(2);
185
186 off_t result = lseek(fd, offs, whence);
187
188 return (result == (off_t)-1) ? -errno : result;
189}
190
191
192SyscallReturn
193_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
194{
195 int fd = p->sim_fd(tc->getSyscallArg(0));
196 uint64_t offset_high = tc->getSyscallArg(1);
197 uint32_t offset_low = tc->getSyscallArg(2);
198 Addr result_ptr = tc->getSyscallArg(3);
199 int whence = tc->getSyscallArg(4);
200
201 uint64_t offset = (offset_high << 32) | offset_low;
202
203 uint64_t result = lseek(fd, offset, whence);
204 result = TheISA::htog(result);
205
206 if (result == (off_t)-1) {
207 //The seek failed.
208 return -errno;
209 } else {
210 //The seek succeeded.
211 //Copy "result" to "result_ptr"
212 //XXX We'll assume that the size of loff_t is 64 bits on the
213 //target platform
214 BufferArg result_buf(result_ptr, sizeof(result));
215 memcpy(result_buf.bufferPtr(), &result, sizeof(result));
216 result_buf.copyOut(tc->getMemPort());
217 return 0;
218 }
219
220
221 return (result == (off_t)-1) ? -errno : result;
222}
223
224
225SyscallReturn
226munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
227{
228 // given that we don't really implement mmap, munmap is really easy
229 return 0;
230}
231
232
233const char *hostname = "m5.eecs.umich.edu";
234
235SyscallReturn
236gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
237{
238 int name_len = tc->getSyscallArg(1);
239 BufferArg name(tc->getSyscallArg(0), name_len);
240
241 strncpy((char *)name.bufferPtr(), hostname, name_len);
242
243 name.copyOut(tc->getMemPort());
244
245 return 0;
246}
247
248SyscallReturn
249getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
250{
251 int result = 0;
252 unsigned long size = tc->getSyscallArg(1);
253 BufferArg buf(tc->getSyscallArg(0), size);
254
255 // Is current working directory defined?
256 string cwd = p->getcwd();
257 if (!cwd.empty()) {
258 if (cwd.length() >= size) {
259 // Buffer too small
260 return -ERANGE;
261 }
262 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
263 result = cwd.length();
264 }
265 else {
266 if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
267 result = strlen((char *)buf.bufferPtr());
268 }
269 else {
270 result = -1;
271 }
272 }
273
274 buf.copyOut(tc->getMemPort());
275
276 return (result == -1) ? -errno : result;
277}
278
279
280SyscallReturn
281readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
282{
283 string path;
284
285 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
286 return (TheISA::IntReg)-EFAULT;
287
288 // Adjust path for current working directory
289 path = p->fullPath(path);
290
291 size_t bufsiz = tc->getSyscallArg(2);
292 BufferArg buf(tc->getSyscallArg(1), bufsiz);
293
294 int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
295
296 buf.copyOut(tc->getMemPort());
297
298 return (result == -1) ? -errno : result;
299}
300
301SyscallReturn
302unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
303{
304 string path;
305
306 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
307 return (TheISA::IntReg)-EFAULT;
308
309 // Adjust path for current working directory
310 path = p->fullPath(path);
311
312 int result = unlink(path.c_str());
313 return (result == -1) ? -errno : result;
314}
315
316
317SyscallReturn
318mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
319{
320 string path;
321
322 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
323 return (TheISA::IntReg)-EFAULT;
324
325 // Adjust path for current working directory
326 path = p->fullPath(path);
327
328 mode_t mode = tc->getSyscallArg(1);
329
330 int result = mkdir(path.c_str(), mode);
331 return (result == -1) ? -errno : result;
332}
333
334SyscallReturn
335renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
336{
337 string old_name;
338
339 if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0)))
340 return -EFAULT;
341
342 string new_name;
343
344 if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1)))
345 return -EFAULT;
346
347 // Adjust path for current working directory
348 old_name = p->fullPath(old_name);
349 new_name = p->fullPath(new_name);
350
351 int64_t result = rename(old_name.c_str(), new_name.c_str());
352 return (result == -1) ? -errno : result;
353}
354
355SyscallReturn
356truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
357{
358 string path;
359
360 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
361 return -EFAULT;
362
363 off_t length = tc->getSyscallArg(1);
364
365 // Adjust path for current working directory
366 path = p->fullPath(path);
367
368 int result = truncate(path.c_str(), length);
369 return (result == -1) ? -errno : result;
370}
371
372SyscallReturn
373ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
374{
375 int fd = process->sim_fd(tc->getSyscallArg(0));
376
377 if (fd < 0)
378 return -EBADF;
379
380 off_t length = tc->getSyscallArg(1);
381
382 int result = ftruncate(fd, length);
383 return (result == -1) ? -errno : result;
384}
385
386SyscallReturn
387umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
388{
389 // Letting the simulated program change the simulator's umask seems like
390 // a bad idea. Compromise by just returning the current umask but not
391 // changing anything.
392 mode_t oldMask = umask(0);
393 umask(oldMask);
394 return (int)oldMask;
395}
396
397SyscallReturn
398chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
399{
400 string path;
401
402 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
403 return -EFAULT;
404
405 /* XXX endianess */
406 uint32_t owner = tc->getSyscallArg(1);
407 uid_t hostOwner = owner;
408 uint32_t group = tc->getSyscallArg(2);
409 gid_t hostGroup = group;
410
411 // Adjust path for current working directory
412 path = p->fullPath(path);
413
414 int result = chown(path.c_str(), hostOwner, hostGroup);
415 return (result == -1) ? -errno : result;
416}
417
418SyscallReturn
419fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
420{
421 int fd = process->sim_fd(tc->getSyscallArg(0));
422
423 if (fd < 0)
424 return -EBADF;
425
426 /* XXX endianess */
427 uint32_t owner = tc->getSyscallArg(1);
428 uid_t hostOwner = owner;
429 uint32_t group = tc->getSyscallArg(2);
430 gid_t hostGroup = group;
431
432 int result = fchown(fd, hostOwner, hostGroup);
433 return (result == -1) ? -errno : result;
434}
435
436
437SyscallReturn
438dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
439{
440 int fd = process->sim_fd(tc->getSyscallArg(0));
441 if (fd < 0)
442 return -EBADF;
443
444 Process::FdMap *fdo = process->sim_fd_obj(tc->getSyscallArg(0));
445
446 int result = dup(fd);
447 return (result == -1) ? -errno : process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
448}
449
450
451SyscallReturn
452fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
453 ThreadContext *tc)
454{
455 int fd = tc->getSyscallArg(0);
456
457 if (fd < 0 || process->sim_fd(fd) < 0)
458 return -EBADF;
459
460 int cmd = tc->getSyscallArg(1);
461 switch (cmd) {
462 case 0: // F_DUPFD
463 // if we really wanted to support this, we'd need to do it
464 // in the target fd space.
465 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd);
466 return -EMFILE;
467
468 case 1: // F_GETFD (get close-on-exec flag)
469 case 2: // F_SETFD (set close-on-exec flag)
470 return 0;
471
472 case 3: // F_GETFL (get file flags)
473 case 4: // F_SETFL (set file flags)
474 // not sure if this is totally valid, but we'll pass it through
475 // to the underlying OS
476 warn("fcntl(%d, %d) passed through to host\n", fd, cmd);
477 return fcntl(process->sim_fd(fd), cmd);
478 // return 0;
479
480 case 7: // F_GETLK (get lock)
481 case 8: // F_SETLK (set lock)
482 case 9: // F_SETLKW (set lock and wait)
483 // don't mess with file locking... just act like it's OK
484 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd);
485 return 0;
486
487 default:
488 warn("Unknown fcntl command %d\n", cmd);
489 return 0;
490 }
491}
492
493SyscallReturn
494fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
495 ThreadContext *tc)
496{
497 int fd = tc->getSyscallArg(0);
498
499 if (fd < 0 || process->sim_fd(fd) < 0)
500 return -EBADF;
501
502 int cmd = tc->getSyscallArg(1);
503 switch (cmd) {
504 case 33: //F_GETLK64
505 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
506 return -EMFILE;
507
508 case 34: // F_SETLK64
509 case 35: // F_SETLKW64
510 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
511 return -EMFILE;
512
513 default:
514 // not sure if this is totally valid, but we'll pass it through
515 // to the underlying OS
516 warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
517 return fcntl(process->sim_fd(fd), cmd);
518 // return 0;
519 }
520}
521
522SyscallReturn
523pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
524 ThreadContext *tc)
525{
526 int fds[2], sim_fds[2];
527 int pipe_retval = pipe(fds);
528
529 if (pipe_retval < 0) {
530 // error
531 return pipe_retval;
532 }
533
534 sim_fds[0] = process->alloc_fd(fds[0], "PIPE-READ", O_WRONLY, -1, true);
535 sim_fds[1] = process->alloc_fd(fds[1], "PIPE-WRITE", O_RDONLY, -1, true);
536
537 process->setReadPipeSource(sim_fds[0], sim_fds[1]);
538 // Alpha Linux convention for pipe() is that fd[0] is returned as
539 // the return value of the function, and fd[1] is returned in r20.
540 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
541 return sim_fds[0];
542}
543
544
545SyscallReturn
546getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
547 ThreadContext *tc)
548{
549 // Make up a PID. There's no interprocess communication in
550 // fake_syscall mode, so there's no way for a process to know it's
551 // not getting a unique value.
552
553 tc->setIntReg(SyscallPseudoReturnReg, process->ppid());
554 return process->pid();
555}
556
557
558SyscallReturn
559getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
560 ThreadContext *tc)
561{
562 // Make up a UID and EUID... it shouldn't matter, and we want the
563 // simulation to be deterministic.
564
565 // EUID goes in r20.
566 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
567 return process->uid(); // UID
568}
569
570
571SyscallReturn
572getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
573 ThreadContext *tc)
574{
575 // Get current group ID. EGID goes in r20.
576 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID
577 return process->gid();
578}
579
580
581SyscallReturn
582setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
583 ThreadContext *tc)
584{
585 // can't fathom why a benchmark would call this.
586 warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0));
587 return 0;
588}
589
590SyscallReturn
591getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
592 ThreadContext *tc)
593{
594 // Make up a PID. There's no interprocess communication in
595 // fake_syscall mode, so there's no way for a process to know it's
596 // not getting a unique value.
597
598 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID
599 return process->pid();
600}
601
602SyscallReturn
603getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
604 ThreadContext *tc)
605{
606 return process->ppid();
607}
608
609SyscallReturn
610getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
611 ThreadContext *tc)
612{
613 return process->uid(); // UID
614}
615
616SyscallReturn
617geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
618 ThreadContext *tc)
619{
620 return process->euid(); // UID
621}
622
623SyscallReturn
624getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
625 ThreadContext *tc)
626{
627 return process->gid();
628}
629
630SyscallReturn
631getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
632 ThreadContext *tc)
633{
634 return process->egid();
635}
636
637