syscall_emul.cc revision 2495
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 29#include <fcntl.h> 30#include <unistd.h> 31 32#include <string> 33#include <iostream> 34 35#include "sim/syscall_emul.hh" 36#include "base/chunk_generator.hh" 37#include "base/trace.hh" 38#include "cpu/exec_context.hh" 39#include "cpu/base.hh" 40#include "mem/page_table.hh" 41#include "sim/process.hh" 42 43#include "sim/sim_events.hh" 44 45using namespace std; 46using namespace TheISA; 47 48void 49SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) 50{ 51 DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n", 52 curTick,xc->getCpuPtr()->name(), name, 53 xc->getSyscallArg(0),xc->getSyscallArg(1), 54 xc->getSyscallArg(2),xc->getSyscallArg(3)); 55 56 SyscallReturn retval = (*funcPtr)(this, callnum, process, xc); 57 58 DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n", 59 curTick,xc->getCpuPtr()->name(), name, retval.value()); 60 61 if (!(flags & SyscallDesc::SuppressReturnValue)) 62 xc->setSyscallReturn(retval); 63} 64 65 66SyscallReturn 67unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, 68 ExecContext *xc) 69{ 70 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 71 72 return 1; 73} 74 75 76SyscallReturn 77ignoreFunc(SyscallDesc *desc, int callnum, Process *process, 78 ExecContext *xc) 79{ 80 warn("ignoring syscall %s(%d, %d, ...)", desc->name, 81 xc->getSyscallArg(0), xc->getSyscallArg(1)); 82 83 return 0; 84} 85 86 87SyscallReturn 88exitFunc(SyscallDesc *desc, int callnum, Process *process, 89 ExecContext *xc) 90{ 91 new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff); 92 93 return 1; 94} 95 96 97SyscallReturn 98getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 99{ 100 return (int)VMPageSize; 101} 102 103 104SyscallReturn 105obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 106{ 107 Addr junk; 108 109 // change brk addr to first arg 110 Addr new_brk = xc->getSyscallArg(0); 111 if (new_brk != 0) { 112 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, 113 VMPageSize); !gen.done(); gen.next()) { 114 if (!p->pTable->translate(gen.addr(), junk)) 115 p->pTable->allocate(roundDown(gen.addr(), VMPageSize), 116 VMPageSize); 117 } 118 p->brk_point = new_brk; 119 } 120 DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); 121 return p->brk_point; 122} 123 124 125SyscallReturn 126closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 127{ 128 int target_fd = xc->getSyscallArg(0); 129 int status = close(p->sim_fd(target_fd)); 130 if (status >= 0) 131 p->free_fd(target_fd); 132 return status; 133} 134 135 136SyscallReturn 137readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 138{ 139 int fd = p->sim_fd(xc->getSyscallArg(0)); 140 int nbytes = xc->getSyscallArg(2); 141 BufferArg bufArg(xc->getSyscallArg(1), nbytes); 142 143 int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); 144 145 if (bytes_read != -1) 146 bufArg.copyOut(xc->getMemPort()); 147 148 return bytes_read; 149} 150 151SyscallReturn 152writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 153{ 154 int fd = p->sim_fd(xc->getSyscallArg(0)); 155 int nbytes = xc->getSyscallArg(2); 156 BufferArg bufArg(xc->getSyscallArg(1), nbytes); 157 158 bufArg.copyIn(xc->getMemPort()); 159 160 int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); 161 162 fsync(fd); 163 164 return bytes_written; 165} 166 167 168SyscallReturn 169lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 170{ 171 int fd = p->sim_fd(xc->getSyscallArg(0)); 172 uint64_t offs = xc->getSyscallArg(1); 173 int whence = xc->getSyscallArg(2); 174 175 off_t result = lseek(fd, offs, whence); 176 177 return (result == (off_t)-1) ? -errno : result; 178} 179 180 181SyscallReturn 182munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 183{ 184 // given that we don't really implement mmap, munmap is really easy 185 return 0; 186} 187 188 189const char *hostname = "m5.eecs.umich.edu"; 190 191SyscallReturn 192gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 193{ 194 int name_len = xc->getSyscallArg(1); 195 BufferArg name(xc->getSyscallArg(0), name_len); 196 197 strncpy((char *)name.bufferPtr(), hostname, name_len); 198 199 name.copyOut(xc->getMemPort()); 200 201 return 0; 202} 203 204SyscallReturn 205unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 206{ 207 string path; 208 209 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 210 return (TheISA::IntReg)-EFAULT; 211 212 int result = unlink(path.c_str()); 213 return (result == -1) ? -errno : result; 214} 215 216SyscallReturn 217renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 218{ 219 string old_name; 220 221 if (!xc->getMemPort()->tryReadString(old_name, xc->getSyscallArg(0))) 222 return -EFAULT; 223 224 string new_name; 225 226 if (!xc->getMemPort()->tryReadString(new_name, xc->getSyscallArg(1))) 227 return -EFAULT; 228 229 int64_t result = rename(old_name.c_str(), new_name.c_str()); 230 return (result == -1) ? -errno : result; 231} 232 233SyscallReturn 234truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 235{ 236 string path; 237 238 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 239 return -EFAULT; 240 241 off_t length = xc->getSyscallArg(1); 242 243 int result = truncate(path.c_str(), length); 244 return (result == -1) ? -errno : result; 245} 246 247SyscallReturn 248ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) 249{ 250 int fd = process->sim_fd(xc->getSyscallArg(0)); 251 252 if (fd < 0) 253 return -EBADF; 254 255 off_t length = xc->getSyscallArg(1); 256 257 int result = ftruncate(fd, length); 258 return (result == -1) ? -errno : result; 259} 260 261SyscallReturn 262chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 263{ 264 string path; 265 266 if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0))) 267 return -EFAULT; 268 269 /* XXX endianess */ 270 uint32_t owner = xc->getSyscallArg(1); 271 uid_t hostOwner = owner; 272 uint32_t group = xc->getSyscallArg(2); 273 gid_t hostGroup = group; 274 275 int result = chown(path.c_str(), hostOwner, hostGroup); 276 return (result == -1) ? -errno : result; 277} 278 279SyscallReturn 280fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc) 281{ 282 int fd = process->sim_fd(xc->getSyscallArg(0)); 283 284 if (fd < 0) 285 return -EBADF; 286 287 /* XXX endianess */ 288 uint32_t owner = xc->getSyscallArg(1); 289 uid_t hostOwner = owner; 290 uint32_t group = xc->getSyscallArg(2); 291 gid_t hostGroup = group; 292 293 int result = fchown(fd, hostOwner, hostGroup); 294 return (result == -1) ? -errno : result; 295} 296 297 298SyscallReturn 299fcntlFunc(SyscallDesc *desc, int num, Process *process, 300 ExecContext *xc) 301{ 302 int fd = xc->getSyscallArg(0); 303 304 if (fd < 0 || process->sim_fd(fd) < 0) 305 return -EBADF; 306 307 int cmd = xc->getSyscallArg(1); 308 switch (cmd) { 309 case 0: // F_DUPFD 310 // if we really wanted to support this, we'd need to do it 311 // in the target fd space. 312 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", fd); 313 return -EMFILE; 314 315 case 1: // F_GETFD (get close-on-exec flag) 316 case 2: // F_SETFD (set close-on-exec flag) 317 return 0; 318 319 case 3: // F_GETFL (get file flags) 320 case 4: // F_SETFL (set file flags) 321 // not sure if this is totally valid, but we'll pass it through 322 // to the underlying OS 323 warn("fcntl(%d, %d) passed through to host\n", fd, cmd); 324 return fcntl(process->sim_fd(fd), cmd); 325 // return 0; 326 327 case 7: // F_GETLK (get lock) 328 case 8: // F_SETLK (set lock) 329 case 9: // F_SETLKW (set lock and wait) 330 // don't mess with file locking... just act like it's OK 331 warn("File lock call (fcntl(%d, %d)) ignored.\n", fd, cmd); 332 return 0; 333 334 default: 335 warn("Unknown fcntl command %d\n", cmd); 336 return 0; 337 } 338} 339 340SyscallReturn 341pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 342 ExecContext *xc) 343{ 344 int fds[2], sim_fds[2]; 345 int pipe_retval = pipe(fds); 346 347 if (pipe_retval < 0) { 348 // error 349 return pipe_retval; 350 } 351 352 sim_fds[0] = process->alloc_fd(fds[0]); 353 sim_fds[1] = process->alloc_fd(fds[1]); 354 355 // Alpha Linux convention for pipe() is that fd[0] is returned as 356 // the return value of the function, and fd[1] is returned in r20. 357 xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); 358 return sim_fds[0]; 359} 360 361 362SyscallReturn 363getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 364 ExecContext *xc) 365{ 366 // Make up a PID. There's no interprocess communication in 367 // fake_syscall mode, so there's no way for a process to know it's 368 // not getting a unique value. 369 370 xc->setIntReg(SyscallPseudoReturnReg, 99); 371 return 100; 372} 373 374 375SyscallReturn 376getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 377 ExecContext *xc) 378{ 379 // Make up a UID and EUID... it shouldn't matter, and we want the 380 // simulation to be deterministic. 381 382 // EUID goes in r20. 383 xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID 384 return 100; // UID 385} 386 387 388SyscallReturn 389getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 390 ExecContext *xc) 391{ 392 // Get current group ID. EGID goes in r20. 393 xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID 394 return 100; 395} 396 397 398SyscallReturn 399setuidFunc(SyscallDesc *desc, int callnum, Process *process, 400 ExecContext *xc) 401{ 402 // can't fathom why a benchmark would call this. 403 warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0)); 404 return 0; 405} 406 407SyscallReturn 408getpidFunc(SyscallDesc *desc, int callnum, Process *process, 409 ExecContext *xc) 410{ 411 // Make up a PID. There's no interprocess communication in 412 // fake_syscall mode, so there's no way for a process to know it's 413 // not getting a unique value. 414 415 xc->setIntReg(SyscallPseudoReturnReg, 99); //PID 416 return 100; 417} 418 419SyscallReturn 420getppidFunc(SyscallDesc *desc, int callnum, Process *process, 421 ExecContext *xc) 422{ 423 return 99; 424} 425 426SyscallReturn 427getuidFunc(SyscallDesc *desc, int callnum, Process *process, 428 ExecContext *xc) 429{ 430 return 100; // UID 431} 432 433SyscallReturn 434geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 435 ExecContext *xc) 436{ 437 return 100; // UID 438} 439 440SyscallReturn 441getgidFunc(SyscallDesc *desc, int callnum, Process *process, 442 ExecContext *xc) 443{ 444 return 100; 445} 446 447SyscallReturn 448getegidFunc(SyscallDesc *desc, int callnum, Process *process, 449 ExecContext *xc) 450{ 451 return 100; 452} 453 454 455