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