syscall_emul.cc revision 2442
13006SN/A/* 23006SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 34398SN/A * All rights reserved. 411390Ssteve.reinhardt@amd.com * 511390Ssteve.reinhardt@amd.com * Redistribution and use in source and binary forms, with or without 68540SN/A * modification, are permitted provided that the following conditions are 711687Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 811687Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 911687Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 1011687Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 1111687Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 1211390Ssteve.reinhardt@amd.com * neither the name of the copyright holders nor the names of its 1311390Ssteve.reinhardt@amd.com * contributors may be used to endorse or promote products derived from 1410036SAli.Saidi@ARM.com * this software without specific prior written permission. 1510036SAli.Saidi@ARM.com * 1611530Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1711390Ssteve.reinhardt@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1811390Ssteve.reinhardt@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1911390Ssteve.reinhardt@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2011390Ssteve.reinhardt@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2111390Ssteve.reinhardt@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2210488Snilay@cs.wisc.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2310488Snilay@cs.wisc.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2411390Ssteve.reinhardt@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2511390Ssteve.reinhardt@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2611390Ssteve.reinhardt@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2710488Snilay@cs.wisc.edu */ 2810488Snilay@cs.wisc.edu 2911390Ssteve.reinhardt@amd.com#include <fcntl.h> 3011390Ssteve.reinhardt@amd.com#include <unistd.h> 3111390Ssteve.reinhardt@amd.com 3211390Ssteve.reinhardt@amd.com#include <string> 3311390Ssteve.reinhardt@amd.com#include <iostream> 3411390Ssteve.reinhardt@amd.com 3511390Ssteve.reinhardt@amd.com#include "sim/syscall_emul.hh" 3611390Ssteve.reinhardt@amd.com#include "base/trace.hh" 3711390Ssteve.reinhardt@amd.com#include "cpu/exec_context.hh" 3811390Ssteve.reinhardt@amd.com#include "cpu/base.hh" 3911530Sandreas.sandberg@arm.com#include "sim/process.hh" 4010036SAli.Saidi@ARM.com 418540SN/A#include "sim/sim_events.hh" 428540SN/A 438540SN/Ausing namespace std; 448540SN/Ausing namespace TheISA; 458540SN/A 468540SN/Avoid 475510SN/ASyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc) 485510SN/A{ 498540SN/A DPRINTFR(SyscallVerbose, "%s: syscall %s called\n", 508540SN/A xc->getCpuPtr()->name(), name); 518540SN/A 528540SN/A SyscallReturn retval = (*funcPtr)(this, callnum, process, xc); 538540SN/A 548540SN/A DPRINTFR(SyscallVerbose, "%s: syscall %s returns %d\n", 558540SN/A xc->getCpuPtr()->name(), name, retval.value()); 565510SN/A 575510SN/A if (!(flags & SyscallDesc::SuppressReturnValue)) 588540SN/A xc->setSyscallReturn(retval); 5910488Snilay@cs.wisc.edu} 6011530Sandreas.sandberg@arm.com 6111390Ssteve.reinhardt@amd.com 628540SN/ASyscallReturn 637935SN/AunimplementedFunc(SyscallDesc *desc, int callnum, Process *process, 6411390Ssteve.reinhardt@amd.com ExecContext *xc) 6511390Ssteve.reinhardt@amd.com{ 6611390Ssteve.reinhardt@amd.com fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 678540SN/A} 6811390Ssteve.reinhardt@amd.com 6911390Ssteve.reinhardt@amd.com 7011390Ssteve.reinhardt@amd.comSyscallReturn 717935SN/AignoreFunc(SyscallDesc *desc, int callnum, Process *process, 7211390Ssteve.reinhardt@amd.com ExecContext *xc) 7311390Ssteve.reinhardt@amd.com{ 747935SN/A warn("ignoring syscall %s(%d, %d, ...)", desc->name, 757935SN/A xc->getSyscallArg(0), xc->getSyscallArg(1)); 7611390Ssteve.reinhardt@amd.com 7711390Ssteve.reinhardt@amd.com return 0; 7810488Snilay@cs.wisc.edu} 797935SN/A 8011390Ssteve.reinhardt@amd.com 818540SN/ASyscallReturn 828540SN/AexitFunc(SyscallDesc *desc, int callnum, Process *process, 8311390Ssteve.reinhardt@amd.com ExecContext *xc) 8411390Ssteve.reinhardt@amd.com{ 8511390Ssteve.reinhardt@amd.com new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff); 8611390Ssteve.reinhardt@amd.com 8711390Ssteve.reinhardt@amd.com return 1; 8811390Ssteve.reinhardt@amd.com} 8911390Ssteve.reinhardt@amd.com 9011390Ssteve.reinhardt@amd.com 9111390Ssteve.reinhardt@amd.comSyscallReturn 9211687Sandreas.hansson@arm.comgetpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 9311390Ssteve.reinhardt@amd.com{ 9411687Sandreas.hansson@arm.com return (int)VMPageSize; 9511390Ssteve.reinhardt@amd.com} 9611390Ssteve.reinhardt@amd.com 9711390Ssteve.reinhardt@amd.com 9811390Ssteve.reinhardt@amd.comSyscallReturn 9911390Ssteve.reinhardt@amd.comobreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 10011390Ssteve.reinhardt@amd.com{ 10111390Ssteve.reinhardt@amd.com // change brk addr to first arg 10211390Ssteve.reinhardt@amd.com Addr new_brk = xc->getSyscallArg(0); 10311390Ssteve.reinhardt@amd.com if (new_brk != 0) 10411390Ssteve.reinhardt@amd.com { 10511390Ssteve.reinhardt@amd.com p->brk_point = xc->getSyscallArg(0); 10611390Ssteve.reinhardt@amd.com } 10711390Ssteve.reinhardt@amd.com DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point); 10811390Ssteve.reinhardt@amd.com return p->brk_point; 10911390Ssteve.reinhardt@amd.com} 11011390Ssteve.reinhardt@amd.com 11111390Ssteve.reinhardt@amd.com 11211390Ssteve.reinhardt@amd.comSyscallReturn 11311390Ssteve.reinhardt@amd.comcloseFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 11411390Ssteve.reinhardt@amd.com{ 11511390Ssteve.reinhardt@amd.com int target_fd = xc->getSyscallArg(0); 11611390Ssteve.reinhardt@amd.com int status = close(p->sim_fd(target_fd)); 11711390Ssteve.reinhardt@amd.com if (status >= 0) 11811687Sandreas.hansson@arm.com p->free_fd(target_fd); 11911687Sandreas.hansson@arm.com return status; 12010220Sandreas.hansson@arm.com} 12110220Sandreas.hansson@arm.com 12211390Ssteve.reinhardt@amd.com 12311606Sandreas.sandberg@arm.comSyscallReturn 12411606Sandreas.sandberg@arm.comreadFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 12511606Sandreas.sandberg@arm.com{ 12611606Sandreas.sandberg@arm.com int fd = p->sim_fd(xc->getSyscallArg(0)); 12711606Sandreas.sandberg@arm.com int nbytes = xc->getSyscallArg(2); 12811606Sandreas.sandberg@arm.com BufferArg bufArg(xc->getSyscallArg(1), nbytes); 12911530Sandreas.sandberg@arm.com 13011390Ssteve.reinhardt@amd.com int bytes_read = read(fd, bufArg.bufferPtr(), nbytes); 13111390Ssteve.reinhardt@amd.com 13211268Satgutier@umich.edu if (bytes_read != -1) 13311268Satgutier@umich.edu bufArg.copyOut(xc->getMemPort()); 13411390Ssteve.reinhardt@amd.com 13511390Ssteve.reinhardt@amd.com return bytes_read; 13611390Ssteve.reinhardt@amd.com} 13711390Ssteve.reinhardt@amd.com 13811390Ssteve.reinhardt@amd.comSyscallReturn 13911390Ssteve.reinhardt@amd.comwriteFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc) 14011268Satgutier@umich.edu{ 14111570SCurtis.Dunham@arm.com int fd = p->sim_fd(xc->getSyscallArg(0)); 14211390Ssteve.reinhardt@amd.com int nbytes = xc->getSyscallArg(2); 14311606Sandreas.sandberg@arm.com BufferArg bufArg(xc->getSyscallArg(1), nbytes); 14411606Sandreas.sandberg@arm.com 14511268Satgutier@umich.edu bufArg.copyIn(xc->getMemPort()); 14611606Sandreas.sandberg@arm.com 14711606Sandreas.sandberg@arm.com int bytes_written = write(fd, bufArg.bufferPtr(), nbytes); 14811268Satgutier@umich.edu 14911268Satgutier@umich.edu fsync(fd); 15011606Sandreas.sandberg@arm.com 15111390Ssteve.reinhardt@amd.com return bytes_written; 1523006SN/A} 1533006SN/A 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()->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) 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()->readStringFunctional(old_name, xc->getSyscallArg(0)) != NoFault) 209 return -EFAULT; 210 211 string new_name; 212 213 if (xc->getMemPort()->readStringFunctional(new_name, xc->getSyscallArg(1)) != NoFault) 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()->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) 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()->readStringFunctional(path, xc->getSyscallArg(0)) != NoFault) 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