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