1 /* 2 * Syscall implementations for semihosting. 3 * 4 * Copyright (c) 2022 Linaro 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #include "qemu/osdep.h" 10 #include "exec/gdbstub.h" 11 #include "semihosting/guestfd.h" 12 #include "semihosting/syscalls.h" 13 #ifdef CONFIG_USER_ONLY 14 #include "qemu.h" 15 #else 16 #include "semihosting/softmmu-uaccess.h" 17 #endif 18 19 20 /* 21 * Validate or compute the length of the string (including terminator). 22 */ 23 static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen) 24 { 25 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 26 char c; 27 28 if (tlen == 0) { 29 ssize_t slen = target_strlen(str); 30 31 if (slen < 0) { 32 return -EFAULT; 33 } 34 if (slen >= INT32_MAX) { 35 return -ENAMETOOLONG; 36 } 37 return slen + 1; 38 } 39 if (tlen > INT32_MAX) { 40 return -ENAMETOOLONG; 41 } 42 if (get_user_u8(c, str + tlen - 1)) { 43 return -EFAULT; 44 } 45 if (c != 0) { 46 return -EINVAL; 47 } 48 return tlen; 49 } 50 51 static int validate_lock_user_string(char **pstr, CPUState *cs, 52 target_ulong tstr, target_ulong tlen) 53 { 54 int ret = validate_strlen(cs, tstr, tlen); 55 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 56 char *str = NULL; 57 58 if (ret > 0) { 59 str = lock_user(VERIFY_READ, tstr, ret, true); 60 ret = str ? 0 : -EFAULT; 61 } 62 *pstr = str; 63 return ret; 64 } 65 66 /* 67 * TODO: Note that gdb always stores the stat structure big-endian. 68 * So far, that's ok, as the only two targets using this are also 69 * big-endian. Until we do something with gdb, also produce the 70 * same big-endian result from the host. 71 */ 72 static int copy_stat_to_user(CPUState *cs, target_ulong addr, 73 const struct stat *s) 74 { 75 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 76 struct gdb_stat *p; 77 78 if (s->st_dev != (uint32_t)s->st_dev || 79 s->st_ino != (uint32_t)s->st_ino) { 80 return -EOVERFLOW; 81 } 82 83 p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0); 84 if (!p) { 85 return -EFAULT; 86 } 87 88 p->gdb_st_dev = cpu_to_be32(s->st_dev); 89 p->gdb_st_ino = cpu_to_be32(s->st_ino); 90 p->gdb_st_mode = cpu_to_be32(s->st_mode); 91 p->gdb_st_nlink = cpu_to_be32(s->st_nlink); 92 p->gdb_st_uid = cpu_to_be32(s->st_uid); 93 p->gdb_st_gid = cpu_to_be32(s->st_gid); 94 p->gdb_st_rdev = cpu_to_be32(s->st_rdev); 95 p->gdb_st_size = cpu_to_be64(s->st_size); 96 #ifdef _WIN32 97 /* Windows stat is missing some fields. */ 98 p->gdb_st_blksize = 0; 99 p->gdb_st_blocks = 0; 100 #else 101 p->gdb_st_blksize = cpu_to_be64(s->st_blksize); 102 p->gdb_st_blocks = cpu_to_be64(s->st_blocks); 103 #endif 104 p->gdb_st_atime = cpu_to_be32(s->st_atime); 105 p->gdb_st_mtime = cpu_to_be32(s->st_mtime); 106 p->gdb_st_ctime = cpu_to_be32(s->st_ctime); 107 108 unlock_user(p, addr, sizeof(struct gdb_stat)); 109 return 0; 110 } 111 112 /* 113 * GDB semihosting syscall implementations. 114 */ 115 116 static gdb_syscall_complete_cb gdb_open_complete; 117 118 static void gdb_open_cb(CPUState *cs, uint64_t ret, int err) 119 { 120 if (!err) { 121 int guestfd = alloc_guestfd(); 122 associate_guestfd(guestfd, ret); 123 ret = guestfd; 124 } 125 gdb_open_complete(cs, ret, err); 126 } 127 128 static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete, 129 target_ulong fname, target_ulong fname_len, 130 int gdb_flags, int mode) 131 { 132 int len = validate_strlen(cs, fname, fname_len); 133 if (len < 0) { 134 complete(cs, -1, -len); 135 return; 136 } 137 138 gdb_open_complete = complete; 139 gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x", 140 fname, len, (target_ulong)gdb_flags, (target_ulong)mode); 141 } 142 143 static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete, 144 GuestFD *gf) 145 { 146 gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd); 147 } 148 149 static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete, 150 GuestFD *gf, target_ulong buf, target_ulong len) 151 { 152 gdb_do_syscall(complete, "read,%x,%x,%x", 153 (target_ulong)gf->hostfd, buf, len); 154 } 155 156 static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete, 157 GuestFD *gf, target_ulong buf, target_ulong len) 158 { 159 gdb_do_syscall(complete, "write,%x,%x,%x", 160 (target_ulong)gf->hostfd, buf, len); 161 } 162 163 static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 164 GuestFD *gf, int64_t off, int gdb_whence) 165 { 166 gdb_do_syscall(complete, "lseek,%x,%lx,%x", 167 (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence); 168 } 169 170 static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete, 171 GuestFD *gf) 172 { 173 gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd); 174 } 175 176 static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete, 177 GuestFD *gf, target_ulong addr) 178 { 179 gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr); 180 } 181 182 static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete, 183 target_ulong fname, target_ulong fname_len, 184 target_ulong addr) 185 { 186 int len = validate_strlen(cs, fname, fname_len); 187 if (len < 0) { 188 complete(cs, -1, -len); 189 return; 190 } 191 192 gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr); 193 } 194 195 static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete, 196 target_ulong fname, target_ulong fname_len) 197 { 198 int len = validate_strlen(cs, fname, fname_len); 199 if (len < 0) { 200 complete(cs, -1, -len); 201 return; 202 } 203 204 gdb_do_syscall(complete, "unlink,%s", fname, len); 205 } 206 207 static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete, 208 target_ulong oname, target_ulong oname_len, 209 target_ulong nname, target_ulong nname_len) 210 { 211 int olen, nlen; 212 213 olen = validate_strlen(cs, oname, oname_len); 214 if (olen < 0) { 215 complete(cs, -1, -olen); 216 return; 217 } 218 nlen = validate_strlen(cs, nname, nname_len); 219 if (nlen < 0) { 220 complete(cs, -1, -nlen); 221 return; 222 } 223 224 gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen); 225 } 226 227 static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete, 228 target_ulong cmd, target_ulong cmd_len) 229 { 230 int len = validate_strlen(cs, cmd, cmd_len); 231 if (len < 0) { 232 complete(cs, -1, -len); 233 return; 234 } 235 236 gdb_do_syscall(complete, "system,%s", cmd, len); 237 } 238 239 static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, 240 target_ulong tv_addr, target_ulong tz_addr) 241 { 242 gdb_do_syscall(complete, "gettimeofday,%x,%x", tv_addr, tz_addr); 243 } 244 245 /* 246 * Host semihosting syscall implementations. 247 */ 248 249 static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, 250 target_ulong fname, target_ulong fname_len, 251 int gdb_flags, int mode) 252 { 253 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 254 char *p; 255 int ret, host_flags; 256 257 ret = validate_lock_user_string(&p, cs, fname, fname_len); 258 if (ret < 0) { 259 complete(cs, -1, -ret); 260 return; 261 } 262 263 if (gdb_flags & GDB_O_WRONLY) { 264 host_flags = O_WRONLY; 265 } else if (gdb_flags & GDB_O_RDWR) { 266 host_flags = O_RDWR; 267 } else { 268 host_flags = O_RDONLY; 269 } 270 if (gdb_flags & GDB_O_CREAT) { 271 host_flags |= O_CREAT; 272 } 273 if (gdb_flags & GDB_O_TRUNC) { 274 host_flags |= O_TRUNC; 275 } 276 if (gdb_flags & GDB_O_EXCL) { 277 host_flags |= O_EXCL; 278 } 279 280 ret = open(p, host_flags, mode); 281 if (ret < 0) { 282 complete(cs, -1, errno); 283 } else { 284 int guestfd = alloc_guestfd(); 285 associate_guestfd(guestfd, ret); 286 complete(cs, guestfd, 0); 287 } 288 unlock_user(p, fname, 0); 289 } 290 291 static void host_close(CPUState *cs, gdb_syscall_complete_cb complete, 292 GuestFD *gf) 293 { 294 /* 295 * Only close the underlying host fd if it's one we opened on behalf 296 * of the guest in SYS_OPEN. 297 */ 298 if (gf->hostfd != STDIN_FILENO && 299 gf->hostfd != STDOUT_FILENO && 300 gf->hostfd != STDERR_FILENO && 301 close(gf->hostfd) < 0) { 302 complete(cs, -1, errno); 303 } else { 304 complete(cs, 0, 0); 305 } 306 } 307 308 static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, 309 GuestFD *gf, target_ulong buf, target_ulong len) 310 { 311 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 312 void *ptr = lock_user(VERIFY_WRITE, buf, len, 0); 313 ssize_t ret; 314 315 if (!ptr) { 316 complete(cs, -1, EFAULT); 317 return; 318 } 319 do { 320 ret = read(gf->hostfd, ptr, len); 321 } while (ret == -1 && errno == EINTR); 322 if (ret == -1) { 323 complete(cs, -1, errno); 324 unlock_user(ptr, buf, 0); 325 } else { 326 complete(cs, ret, 0); 327 unlock_user(ptr, buf, ret); 328 } 329 } 330 331 static void host_write(CPUState *cs, gdb_syscall_complete_cb complete, 332 GuestFD *gf, target_ulong buf, target_ulong len) 333 { 334 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 335 void *ptr = lock_user(VERIFY_READ, buf, len, 1); 336 ssize_t ret; 337 338 if (!ptr) { 339 complete(cs, -1, EFAULT); 340 return; 341 } 342 ret = write(gf->hostfd, ptr, len); 343 complete(cs, ret, ret == -1 ? errno : 0); 344 unlock_user(ptr, buf, 0); 345 } 346 347 static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 348 GuestFD *gf, int64_t off, int whence) 349 { 350 /* So far, all hosts use the same values. */ 351 QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET); 352 QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR); 353 QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END); 354 355 off_t ret = off; 356 int err = 0; 357 358 if (ret == off) { 359 ret = lseek(gf->hostfd, ret, whence); 360 if (ret == -1) { 361 err = errno; 362 } 363 } else { 364 ret = -1; 365 err = EINVAL; 366 } 367 complete(cs, ret, err); 368 } 369 370 static void host_isatty(CPUState *cs, gdb_syscall_complete_cb complete, 371 GuestFD *gf) 372 { 373 int ret = isatty(gf->hostfd); 374 complete(cs, ret, ret ? 0 : errno); 375 } 376 377 static void host_flen(CPUState *cs, gdb_syscall_complete_cb complete, 378 GuestFD *gf) 379 { 380 struct stat buf; 381 382 if (fstat(gf->hostfd, &buf) < 0) { 383 complete(cs, -1, errno); 384 } else { 385 complete(cs, buf.st_size, 0); 386 } 387 } 388 389 static void host_fstat(CPUState *cs, gdb_syscall_complete_cb complete, 390 GuestFD *gf, target_ulong addr) 391 { 392 struct stat buf; 393 int ret; 394 395 ret = fstat(gf->hostfd, &buf); 396 if (ret) { 397 complete(cs, -1, errno); 398 return; 399 } 400 ret = copy_stat_to_user(cs, addr, &buf); 401 complete(cs, ret ? -1 : 0, ret ? -ret : 0); 402 } 403 404 static void host_stat(CPUState *cs, gdb_syscall_complete_cb complete, 405 target_ulong fname, target_ulong fname_len, 406 target_ulong addr) 407 { 408 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 409 struct stat buf; 410 char *name; 411 int ret, err; 412 413 ret = validate_lock_user_string(&name, cs, fname, fname_len); 414 if (ret < 0) { 415 complete(cs, -1, -ret); 416 return; 417 } 418 419 ret = stat(name, &buf); 420 if (ret) { 421 err = errno; 422 } else { 423 ret = copy_stat_to_user(cs, addr, &buf); 424 err = 0; 425 if (ret < 0) { 426 err = -ret; 427 ret = -1; 428 } 429 } 430 complete(cs, ret, err); 431 unlock_user(name, fname, 0); 432 } 433 434 static void host_remove(CPUState *cs, gdb_syscall_complete_cb complete, 435 target_ulong fname, target_ulong fname_len) 436 { 437 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 438 char *p; 439 int ret; 440 441 ret = validate_lock_user_string(&p, cs, fname, fname_len); 442 if (ret < 0) { 443 complete(cs, -1, -ret); 444 return; 445 } 446 447 ret = remove(p); 448 complete(cs, ret, ret ? errno : 0); 449 unlock_user(p, fname, 0); 450 } 451 452 static void host_rename(CPUState *cs, gdb_syscall_complete_cb complete, 453 target_ulong oname, target_ulong oname_len, 454 target_ulong nname, target_ulong nname_len) 455 { 456 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 457 char *ostr, *nstr; 458 int ret; 459 460 ret = validate_lock_user_string(&ostr, cs, oname, oname_len); 461 if (ret < 0) { 462 complete(cs, -1, -ret); 463 return; 464 } 465 ret = validate_lock_user_string(&nstr, cs, nname, nname_len); 466 if (ret < 0) { 467 unlock_user(ostr, oname, 0); 468 complete(cs, -1, -ret); 469 return; 470 } 471 472 ret = rename(ostr, nstr); 473 complete(cs, ret, ret ? errno : 0); 474 unlock_user(ostr, oname, 0); 475 unlock_user(nstr, nname, 0); 476 } 477 478 static void host_system(CPUState *cs, gdb_syscall_complete_cb complete, 479 target_ulong cmd, target_ulong cmd_len) 480 { 481 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 482 char *p; 483 int ret; 484 485 ret = validate_lock_user_string(&p, cs, cmd, cmd_len); 486 if (ret < 0) { 487 complete(cs, -1, -ret); 488 return; 489 } 490 491 ret = system(p); 492 complete(cs, ret, ret == -1 ? errno : 0); 493 unlock_user(p, cmd, 0); 494 } 495 496 static void host_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, 497 target_ulong tv_addr, target_ulong tz_addr) 498 { 499 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 500 struct gdb_timeval *p; 501 int64_t rt; 502 503 /* GDB fails on non-null TZ, so be consistent. */ 504 if (tz_addr != 0) { 505 complete(cs, -1, EINVAL); 506 return; 507 } 508 509 p = lock_user(VERIFY_WRITE, tv_addr, sizeof(struct gdb_timeval), 0); 510 if (!p) { 511 complete(cs, -1, EFAULT); 512 return; 513 } 514 515 /* TODO: Like stat, gdb always produces big-endian results; match it. */ 516 rt = g_get_real_time(); 517 p->tv_sec = cpu_to_be32(rt / G_USEC_PER_SEC); 518 p->tv_usec = cpu_to_be64(rt % G_USEC_PER_SEC); 519 unlock_user(p, tv_addr, sizeof(struct gdb_timeval)); 520 } 521 522 /* 523 * Static file semihosting syscall implementations. 524 */ 525 526 static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, 527 GuestFD *gf, target_ulong buf, target_ulong len) 528 { 529 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 530 target_ulong rest = gf->staticfile.len - gf->staticfile.off; 531 void *ptr; 532 533 if (len > rest) { 534 len = rest; 535 } 536 ptr = lock_user(VERIFY_WRITE, buf, len, 0); 537 if (!ptr) { 538 complete(cs, -1, EFAULT); 539 return; 540 } 541 memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len); 542 gf->staticfile.off += len; 543 complete(cs, len, 0); 544 unlock_user(ptr, buf, len); 545 } 546 547 static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 548 GuestFD *gf, int64_t off, int gdb_whence) 549 { 550 int64_t ret; 551 552 switch (gdb_whence) { 553 case GDB_SEEK_SET: 554 ret = off; 555 break; 556 case GDB_SEEK_CUR: 557 ret = gf->staticfile.off + off; 558 break; 559 case GDB_SEEK_END: 560 ret = gf->staticfile.len + off; 561 break; 562 default: 563 ret = -1; 564 break; 565 } 566 if (ret >= 0 && ret <= gf->staticfile.len) { 567 gf->staticfile.off = ret; 568 complete(cs, ret, 0); 569 } else { 570 complete(cs, -1, EINVAL); 571 } 572 } 573 574 static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete, 575 GuestFD *gf) 576 { 577 complete(cs, gf->staticfile.len, 0); 578 } 579 580 /* 581 * Syscall entry points. 582 */ 583 584 void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete, 585 target_ulong fname, target_ulong fname_len, 586 int gdb_flags, int mode) 587 { 588 if (use_gdb_syscalls()) { 589 gdb_open(cs, complete, fname, fname_len, gdb_flags, mode); 590 } else { 591 host_open(cs, complete, fname, fname_len, gdb_flags, mode); 592 } 593 } 594 595 void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd) 596 { 597 GuestFD *gf = get_guestfd(fd); 598 599 if (!gf) { 600 complete(cs, -1, EBADF); 601 return; 602 } 603 switch (gf->type) { 604 case GuestFDGDB: 605 gdb_close(cs, complete, gf); 606 break; 607 case GuestFDHost: 608 host_close(cs, complete, gf); 609 break; 610 case GuestFDStatic: 611 complete(cs, 0, 0); 612 break; 613 default: 614 g_assert_not_reached(); 615 } 616 dealloc_guestfd(fd); 617 } 618 619 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete, 620 GuestFD *gf, target_ulong buf, target_ulong len) 621 { 622 /* 623 * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. 624 * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad 625 * idea to do this unconditionally. 626 */ 627 if (len > INT32_MAX) { 628 len = INT32_MAX; 629 } 630 switch (gf->type) { 631 case GuestFDGDB: 632 gdb_read(cs, complete, gf, buf, len); 633 break; 634 case GuestFDHost: 635 host_read(cs, complete, gf, buf, len); 636 break; 637 case GuestFDStatic: 638 staticfile_read(cs, complete, gf, buf, len); 639 break; 640 default: 641 g_assert_not_reached(); 642 } 643 } 644 645 void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete, 646 int fd, target_ulong buf, target_ulong len) 647 { 648 GuestFD *gf = get_guestfd(fd); 649 650 if (gf) { 651 semihost_sys_read_gf(cs, complete, gf, buf, len); 652 } else { 653 complete(cs, -1, EBADF); 654 } 655 } 656 657 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete, 658 GuestFD *gf, target_ulong buf, target_ulong len) 659 { 660 /* 661 * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. 662 * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad 663 * idea to do this unconditionally. 664 */ 665 if (len > INT32_MAX) { 666 len = INT32_MAX; 667 } 668 switch (gf->type) { 669 case GuestFDGDB: 670 gdb_write(cs, complete, gf, buf, len); 671 break; 672 case GuestFDHost: 673 host_write(cs, complete, gf, buf, len); 674 break; 675 case GuestFDStatic: 676 /* Static files are never open for writing: EBADF. */ 677 complete(cs, -1, EBADF); 678 break; 679 default: 680 g_assert_not_reached(); 681 } 682 } 683 684 void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete, 685 int fd, target_ulong buf, target_ulong len) 686 { 687 GuestFD *gf = get_guestfd(fd); 688 689 if (gf) { 690 semihost_sys_write_gf(cs, complete, gf, buf, len); 691 } else { 692 complete(cs, -1, EBADF); 693 } 694 } 695 696 void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 697 int fd, int64_t off, int gdb_whence) 698 { 699 GuestFD *gf = get_guestfd(fd); 700 701 if (!gf) { 702 complete(cs, -1, EBADF); 703 return; 704 } 705 switch (gf->type) { 706 case GuestFDGDB: 707 gdb_lseek(cs, complete, gf, off, gdb_whence); 708 return; 709 case GuestFDHost: 710 host_lseek(cs, complete, gf, off, gdb_whence); 711 break; 712 case GuestFDStatic: 713 staticfile_lseek(cs, complete, gf, off, gdb_whence); 714 break; 715 default: 716 g_assert_not_reached(); 717 } 718 } 719 720 void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd) 721 { 722 GuestFD *gf = get_guestfd(fd); 723 724 if (!gf) { 725 complete(cs, 0, EBADF); 726 return; 727 } 728 switch (gf->type) { 729 case GuestFDGDB: 730 gdb_isatty(cs, complete, gf); 731 break; 732 case GuestFDHost: 733 host_isatty(cs, complete, gf); 734 break; 735 case GuestFDStatic: 736 complete(cs, 0, ENOTTY); 737 break; 738 default: 739 g_assert_not_reached(); 740 } 741 } 742 743 void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb, 744 gdb_syscall_complete_cb flen_cb, int fd, 745 target_ulong fstat_addr) 746 { 747 GuestFD *gf = get_guestfd(fd); 748 749 if (!gf) { 750 flen_cb(cs, -1, EBADF); 751 return; 752 } 753 switch (gf->type) { 754 case GuestFDGDB: 755 gdb_fstat(cs, fstat_cb, gf, fstat_addr); 756 break; 757 case GuestFDHost: 758 host_flen(cs, flen_cb, gf); 759 break; 760 case GuestFDStatic: 761 staticfile_flen(cs, flen_cb, gf); 762 break; 763 default: 764 g_assert_not_reached(); 765 } 766 } 767 768 void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete, 769 int fd, target_ulong addr) 770 { 771 GuestFD *gf = get_guestfd(fd); 772 773 if (!gf) { 774 complete(cs, -1, EBADF); 775 return; 776 } 777 switch (gf->type) { 778 case GuestFDGDB: 779 gdb_fstat(cs, complete, gf, addr); 780 break; 781 case GuestFDHost: 782 host_fstat(cs, complete, gf, addr); 783 break; 784 case GuestFDStatic: 785 default: 786 g_assert_not_reached(); 787 } 788 } 789 790 void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete, 791 target_ulong fname, target_ulong fname_len, 792 target_ulong addr) 793 { 794 if (use_gdb_syscalls()) { 795 gdb_stat(cs, complete, fname, fname_len, addr); 796 } else { 797 host_stat(cs, complete, fname, fname_len, addr); 798 } 799 } 800 801 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete, 802 target_ulong fname, target_ulong fname_len) 803 { 804 if (use_gdb_syscalls()) { 805 gdb_remove(cs, complete, fname, fname_len); 806 } else { 807 host_remove(cs, complete, fname, fname_len); 808 } 809 } 810 811 void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete, 812 target_ulong oname, target_ulong oname_len, 813 target_ulong nname, target_ulong nname_len) 814 { 815 if (use_gdb_syscalls()) { 816 gdb_rename(cs, complete, oname, oname_len, nname, nname_len); 817 } else { 818 host_rename(cs, complete, oname, oname_len, nname, nname_len); 819 } 820 } 821 822 void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete, 823 target_ulong cmd, target_ulong cmd_len) 824 { 825 if (use_gdb_syscalls()) { 826 gdb_system(cs, complete, cmd, cmd_len); 827 } else { 828 host_system(cs, complete, cmd, cmd_len); 829 } 830 } 831 832 void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, 833 target_ulong tv_addr, target_ulong tz_addr) 834 { 835 if (use_gdb_syscalls()) { 836 gdb_gettimeofday(cs, complete, tv_addr, tz_addr); 837 } else { 838 host_gettimeofday(cs, complete, tv_addr, tz_addr); 839 } 840 } 841