syscall_emul.cc revision 2707:ee2a3f82ac56
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 * Korey Sewell 31 */ 32 33#include <fcntl.h> 34#include <unistd.h> 35 36#include <string> 37#include <iostream> 38 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" 46 47#include "sim/sim_events.hh" 48 49using namespace std; 50using namespace TheISA; 51 52void 53SyscallDesc::doSyscall(int callnum, Process *process, ThreadContext *tc) 54{ 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)); 59 60 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); 61 62 DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n", 63 curTick,tc->getCpuPtr()->name(), name, retval.value()); 64 65 if (!(flags & SyscallDesc::SuppressReturnValue)) 66 tc->setSyscallReturn(retval); 67} 68 69 70SyscallReturn 71unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, 72 ThreadContext *tc) 73{ 74 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 75 76 return 1; 77} 78 79 80SyscallReturn 81ignoreFunc(SyscallDesc *desc, int callnum, Process *process, 82 ThreadContext *tc) 83{ 84 warn("ignoring syscall %s(%d, %d, ...)", desc->name, 85 tc->getSyscallArg(0), tc->getSyscallArg(1)); 86 87 return 0; 88} 89 90 91SyscallReturn 92exitFunc(SyscallDesc *desc, int callnum, Process *process, 93 ThreadContext *tc) 94{ 95 new SimExitEvent("target called exit()", tc->getSyscallArg(0) & 0xff); 96 97 return 1; 98} 99 100 101SyscallReturn 102getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 103{ 104 return (int)VMPageSize; 105} 106 107 108SyscallReturn 109obreakFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 110{ 111 Addr junk; 112 113 // change brk addr to first arg 114 Addr new_brk = tc->getSyscallArg(0); 115 if (new_brk != 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), 120 VMPageSize); 121 } 122 p->brk_point = new_brk; 123 } 124 DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); 125 return p->brk_point; 126} 127 128 129SyscallReturn 130closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 131{ 132 int target_fd = tc->getSyscallArg(0); 133 int status = close(p->sim_fd(target_fd)); 134 if (status >= 0) 135 p->free_fd(target_fd); 136 return status; 137} 138 139 140SyscallReturn 141readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 142{ 143 int fd = p->sim_fd(tc->getSyscallArg(0)); 144 int nbytes = tc->getSyscallArg(2); 145 BufferArg bufArg(tc->getSyscallArg(1), nbytes); 146 147 int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); 148 149 if (bytes_read != -1) 150 bufArg.copyOut(tc->getMemPort()); 151 152 return bytes_read; 153} 154 155SyscallReturn 156writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 157{ 158 int fd = p->sim_fd(tc->getSyscallArg(0)); 159 int nbytes = tc->getSyscallArg(2); 160 BufferArg bufArg(tc->getSyscallArg(1), nbytes); 161 162 bufArg.copyIn(tc->getMemPort()); 163 164 int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); 165 166 fsync(fd); 167 168 return bytes_written; 169} 170 171 172SyscallReturn 173lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 174{ 175 int fd = p->sim_fd(tc->getSyscallArg(0)); 176 uint64_t offs = tc->getSyscallArg(1); 177 int whence = tc->getSyscallArg(2); 178 179 off_t result = lseek(fd, offs, whence); 180 181 return (result == (off_t)-1) ? -errno : result; 182} 183 184 185SyscallReturn 186munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 187{ 188 // given that we don't really implement mmap, munmap is really easy 189 return 0; 190} 191 192 193const char *hostname = "m5.eecs.umich.edu"; 194 195SyscallReturn 196gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 197{ 198 int name_len = tc->getSyscallArg(1); 199 BufferArg name(tc->getSyscallArg(0), name_len); 200 201 strncpy((char *)name.bufferPtr(), hostname, name_len); 202 203 name.copyOut(tc->getMemPort()); 204 205 return 0; 206} 207 208SyscallReturn 209unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 210{ 211 string path; 212 213 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 214 return (TheISA::IntReg)-EFAULT; 215 216 int result = unlink(path.c_str()); 217 return (result == -1) ? -errno : result; 218} 219 220SyscallReturn 221renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 222{ 223 string old_name; 224 225 if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0))) 226 return -EFAULT; 227 228 string new_name; 229 230 if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1))) 231 return -EFAULT; 232 233 int64_t result = rename(old_name.c_str(), new_name.c_str()); 234 return (result == -1) ? -errno : result; 235} 236 237SyscallReturn 238truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 239{ 240 string path; 241 242 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 243 return -EFAULT; 244 245 off_t length = tc->getSyscallArg(1); 246 247 int result = truncate(path.c_str(), length); 248 return (result == -1) ? -errno : result; 249} 250 251SyscallReturn 252ftruncateFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 253{ 254 int fd = process->sim_fd(tc->getSyscallArg(0)); 255 256 if (fd < 0) 257 return -EBADF; 258 259 off_t length = tc->getSyscallArg(1); 260 261 int result = ftruncate(fd, length); 262 return (result == -1) ? -errno : result; 263} 264 265SyscallReturn 266chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 267{ 268 string path; 269 270 if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0))) 271 return -EFAULT; 272 273 /* XXX endianess */ 274 uint32_t owner = tc->getSyscallArg(1); 275 uid_t hostOwner = owner; 276 uint32_t group = tc->getSyscallArg(2); 277 gid_t hostGroup = group; 278 279 int result = chown(path.c_str(), hostOwner, hostGroup); 280 return (result == -1) ? -errno : result; 281} 282 283SyscallReturn 284fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 285{ 286 int fd = process->sim_fd(tc->getSyscallArg(0)); 287 288 if (fd < 0) 289 return -EBADF; 290 291 /* XXX endianess */ 292 uint32_t owner = tc->getSyscallArg(1); 293 uid_t hostOwner = owner; 294 uint32_t group = tc->getSyscallArg(2); 295 gid_t hostGroup = group; 296 297 int result = fchown(fd, hostOwner, hostGroup); 298 return (result == -1) ? -errno : result; 299} 300 301 302SyscallReturn 303fcntlFunc(SyscallDesc *desc, int num, Process *process, 304 ThreadContext *tc) 305{ 306 int fd = tc->getSyscallArg(0); 307 308 if (fd < 0 || process->sim_fd(fd) < 0) 309 return -EBADF; 310 311 int cmd = tc->getSyscallArg(1); 312 switch (cmd) { 313 case 0: // F_DUPFD 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); 317 return -EMFILE; 318 319 case 1: // F_GETFD (get close-on-exec flag) 320 case 2: // F_SETFD (set close-on-exec flag) 321 return 0; 322 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); 329 // return 0; 330 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); 336 return 0; 337 338 default: 339 warn("Unknown fcntl command %d\n", cmd); 340 return 0; 341 } 342} 343 344SyscallReturn 345fcntl64Func(SyscallDesc *desc, int num, Process *process, 346 ThreadContext *tc) 347{ 348 int fd = tc->getSyscallArg(0); 349 350 if (fd < 0 || process->sim_fd(fd) < 0) 351 return -EBADF; 352 353 int cmd = tc->getSyscallArg(1); 354 switch (cmd) { 355 case 33: //F_GETLK64 356 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd); 357 return -EMFILE; 358 359 case 34: // F_SETLK64 360 case 35: // F_SETLKW64 361 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd); 362 return -EMFILE; 363 364 default: 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); 369 // return 0; 370 } 371} 372 373SyscallReturn 374pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 375 ThreadContext *tc) 376{ 377 int fds[2], sim_fds[2]; 378 int pipe_retval = pipe(fds); 379 380 if (pipe_retval < 0) { 381 // error 382 return pipe_retval; 383 } 384 385 sim_fds[0] = process->alloc_fd(fds[0]); 386 sim_fds[1] = process->alloc_fd(fds[1]); 387 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]); 391 return sim_fds[0]; 392} 393 394 395SyscallReturn 396getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 397 ThreadContext *tc) 398{ 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. 402 403 tc->setIntReg(SyscallPseudoReturnReg, 99); 404 return 100; 405} 406 407 408SyscallReturn 409getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 410 ThreadContext *tc) 411{ 412 // Make up a UID and EUID... it shouldn't matter, and we want the 413 // simulation to be deterministic. 414 415 // EUID goes in r20. 416 tc->setIntReg(SyscallPseudoReturnReg, 100); //EUID 417 return 100; // UID 418} 419 420 421SyscallReturn 422getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 423 ThreadContext *tc) 424{ 425 // Get current group ID. EGID goes in r20. 426 tc->setIntReg(SyscallPseudoReturnReg, 100); //EGID 427 return 100; 428} 429 430 431SyscallReturn 432setuidFunc(SyscallDesc *desc, int callnum, Process *process, 433 ThreadContext *tc) 434{ 435 // can't fathom why a benchmark would call this. 436 warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0)); 437 return 0; 438} 439 440SyscallReturn 441getpidFunc(SyscallDesc *desc, int callnum, Process *process, 442 ThreadContext *tc) 443{ 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. 447 448 tc->setIntReg(SyscallPseudoReturnReg, 99); //PID 449 return 100; 450} 451 452SyscallReturn 453getppidFunc(SyscallDesc *desc, int callnum, Process *process, 454 ThreadContext *tc) 455{ 456 return 99; 457} 458 459SyscallReturn 460getuidFunc(SyscallDesc *desc, int callnum, Process *process, 461 ThreadContext *tc) 462{ 463 return 100; // UID 464} 465 466SyscallReturn 467geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 468 ThreadContext *tc) 469{ 470 return 100; // UID 471} 472 473SyscallReturn 474getgidFunc(SyscallDesc *desc, int callnum, Process *process, 475 ThreadContext *tc) 476{ 477 return 100; 478} 479 480SyscallReturn 481getegidFunc(SyscallDesc *desc, int callnum, Process *process, 482 ThreadContext *tc) 483{ 484 return 100; 485} 486 487 488