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 "cpu.h" 11 #include "gdbstub/syscalls.h" 12 #include "semihosting/guestfd.h" 13 #include "semihosting/syscalls.h" 14 #include "semihosting/console.h" 15 #ifdef CONFIG_USER_ONLY 16 #include "qemu.h" 17 #else 18 #include "semihosting/softmmu-uaccess.h" 19 #endif 20 21 22 /* 23 * Validate or compute the length of the string (including terminator). 24 */ 25 static int validate_strlen(CPUState *cs, target_ulong str, target_ulong tlen) 26 { 27 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 28 char c; 29 30 if (tlen == 0) { 31 ssize_t slen = target_strlen(str); 32 33 if (slen < 0) { 34 return -EFAULT; 35 } 36 if (slen >= INT32_MAX) { 37 return -ENAMETOOLONG; 38 } 39 return slen + 1; 40 } 41 if (tlen > INT32_MAX) { 42 return -ENAMETOOLONG; 43 } 44 if (get_user_u8(c, str + tlen - 1)) { 45 return -EFAULT; 46 } 47 if (c != 0) { 48 return -EINVAL; 49 } 50 return tlen; 51 } 52 53 static int validate_lock_user_string(char **pstr, CPUState *cs, 54 target_ulong tstr, target_ulong tlen) 55 { 56 int ret = validate_strlen(cs, tstr, tlen); 57 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 58 char *str = NULL; 59 60 if (ret > 0) { 61 str = lock_user(VERIFY_READ, tstr, ret, true); 62 ret = str ? 0 : -EFAULT; 63 } 64 *pstr = str; 65 return ret; 66 } 67 68 /* 69 * TODO: Note that gdb always stores the stat structure big-endian. 70 * So far, that's ok, as the only two targets using this are also 71 * big-endian. Until we do something with gdb, also produce the 72 * same big-endian result from the host. 73 */ 74 static int copy_stat_to_user(CPUState *cs, target_ulong addr, 75 const struct stat *s) 76 { 77 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 78 struct gdb_stat *p; 79 80 if (s->st_dev != (uint32_t)s->st_dev || 81 s->st_ino != (uint32_t)s->st_ino) { 82 return -EOVERFLOW; 83 } 84 85 p = lock_user(VERIFY_WRITE, addr, sizeof(struct gdb_stat), 0); 86 if (!p) { 87 return -EFAULT; 88 } 89 90 p->gdb_st_dev = cpu_to_be32(s->st_dev); 91 p->gdb_st_ino = cpu_to_be32(s->st_ino); 92 p->gdb_st_mode = cpu_to_be32(s->st_mode); 93 p->gdb_st_nlink = cpu_to_be32(s->st_nlink); 94 p->gdb_st_uid = cpu_to_be32(s->st_uid); 95 p->gdb_st_gid = cpu_to_be32(s->st_gid); 96 p->gdb_st_rdev = cpu_to_be32(s->st_rdev); 97 p->gdb_st_size = cpu_to_be64(s->st_size); 98 #ifdef _WIN32 99 /* Windows stat is missing some fields. */ 100 p->gdb_st_blksize = 0; 101 p->gdb_st_blocks = 0; 102 #else 103 p->gdb_st_blksize = cpu_to_be64(s->st_blksize); 104 p->gdb_st_blocks = cpu_to_be64(s->st_blocks); 105 #endif 106 p->gdb_st_atime = cpu_to_be32(s->st_atime); 107 p->gdb_st_mtime = cpu_to_be32(s->st_mtime); 108 p->gdb_st_ctime = cpu_to_be32(s->st_ctime); 109 110 unlock_user(p, addr, sizeof(struct gdb_stat)); 111 return 0; 112 } 113 114 /* 115 * GDB semihosting syscall implementations. 116 */ 117 118 static gdb_syscall_complete_cb gdb_open_complete; 119 120 static void gdb_open_cb(CPUState *cs, uint64_t ret, int err) 121 { 122 if (!err) { 123 int guestfd = alloc_guestfd(); 124 associate_guestfd(guestfd, ret); 125 ret = guestfd; 126 } 127 gdb_open_complete(cs, ret, err); 128 } 129 130 static void gdb_open(CPUState *cs, gdb_syscall_complete_cb complete, 131 target_ulong fname, target_ulong fname_len, 132 int gdb_flags, int mode) 133 { 134 int len = validate_strlen(cs, fname, fname_len); 135 if (len < 0) { 136 complete(cs, -1, -len); 137 return; 138 } 139 140 gdb_open_complete = complete; 141 gdb_do_syscall(gdb_open_cb, "open,%s,%x,%x", 142 fname, len, (target_ulong)gdb_flags, (target_ulong)mode); 143 } 144 145 static void gdb_close(CPUState *cs, gdb_syscall_complete_cb complete, 146 GuestFD *gf) 147 { 148 gdb_do_syscall(complete, "close,%x", (target_ulong)gf->hostfd); 149 } 150 151 static void gdb_read(CPUState *cs, gdb_syscall_complete_cb complete, 152 GuestFD *gf, target_ulong buf, target_ulong len) 153 { 154 gdb_do_syscall(complete, "read,%x,%x,%x", 155 (target_ulong)gf->hostfd, buf, len); 156 } 157 158 static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete, 159 GuestFD *gf, target_ulong buf, target_ulong len) 160 { 161 gdb_do_syscall(complete, "write,%x,%x,%x", 162 (target_ulong)gf->hostfd, buf, len); 163 } 164 165 static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 166 GuestFD *gf, int64_t off, int gdb_whence) 167 { 168 gdb_do_syscall(complete, "lseek,%x,%lx,%x", 169 (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence); 170 } 171 172 static void gdb_isatty(CPUState *cs, gdb_syscall_complete_cb complete, 173 GuestFD *gf) 174 { 175 gdb_do_syscall(complete, "isatty,%x", (target_ulong)gf->hostfd); 176 } 177 178 static void gdb_fstat(CPUState *cs, gdb_syscall_complete_cb complete, 179 GuestFD *gf, target_ulong addr) 180 { 181 gdb_do_syscall(complete, "fstat,%x,%x", (target_ulong)gf->hostfd, addr); 182 } 183 184 static void gdb_stat(CPUState *cs, gdb_syscall_complete_cb complete, 185 target_ulong fname, target_ulong fname_len, 186 target_ulong addr) 187 { 188 int len = validate_strlen(cs, fname, fname_len); 189 if (len < 0) { 190 complete(cs, -1, -len); 191 return; 192 } 193 194 gdb_do_syscall(complete, "stat,%s,%x", fname, len, addr); 195 } 196 197 static void gdb_remove(CPUState *cs, gdb_syscall_complete_cb complete, 198 target_ulong fname, target_ulong fname_len) 199 { 200 int len = validate_strlen(cs, fname, fname_len); 201 if (len < 0) { 202 complete(cs, -1, -len); 203 return; 204 } 205 206 gdb_do_syscall(complete, "unlink,%s", fname, len); 207 } 208 209 static void gdb_rename(CPUState *cs, gdb_syscall_complete_cb complete, 210 target_ulong oname, target_ulong oname_len, 211 target_ulong nname, target_ulong nname_len) 212 { 213 int olen, nlen; 214 215 olen = validate_strlen(cs, oname, oname_len); 216 if (olen < 0) { 217 complete(cs, -1, -olen); 218 return; 219 } 220 nlen = validate_strlen(cs, nname, nname_len); 221 if (nlen < 0) { 222 complete(cs, -1, -nlen); 223 return; 224 } 225 226 gdb_do_syscall(complete, "rename,%s,%s", oname, olen, nname, nlen); 227 } 228 229 static void gdb_system(CPUState *cs, gdb_syscall_complete_cb complete, 230 target_ulong cmd, target_ulong cmd_len) 231 { 232 int len = validate_strlen(cs, cmd, cmd_len); 233 if (len < 0) { 234 complete(cs, -1, -len); 235 return; 236 } 237 238 gdb_do_syscall(complete, "system,%s", cmd, len); 239 } 240 241 static void gdb_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, 242 target_ulong tv_addr, target_ulong tz_addr) 243 { 244 gdb_do_syscall(complete, "gettimeofday,%x,%x", tv_addr, tz_addr); 245 } 246 247 /* 248 * Host semihosting syscall implementations. 249 */ 250 251 static void host_open(CPUState *cs, gdb_syscall_complete_cb complete, 252 target_ulong fname, target_ulong fname_len, 253 int gdb_flags, int mode) 254 { 255 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 256 char *p; 257 int ret, host_flags = O_BINARY; 258 259 ret = validate_lock_user_string(&p, cs, fname, fname_len); 260 if (ret < 0) { 261 complete(cs, -1, -ret); 262 return; 263 } 264 265 if (gdb_flags & GDB_O_WRONLY) { 266 host_flags |= O_WRONLY; 267 } else if (gdb_flags & GDB_O_RDWR) { 268 host_flags |= O_RDWR; 269 } else { 270 host_flags |= O_RDONLY; 271 } 272 if (gdb_flags & GDB_O_CREAT) { 273 host_flags |= O_CREAT; 274 } 275 if (gdb_flags & GDB_O_TRUNC) { 276 host_flags |= O_TRUNC; 277 } 278 if (gdb_flags & GDB_O_EXCL) { 279 host_flags |= O_EXCL; 280 } 281 282 ret = open(p, host_flags, mode); 283 if (ret < 0) { 284 complete(cs, -1, errno); 285 } else { 286 int guestfd = alloc_guestfd(); 287 associate_guestfd(guestfd, ret); 288 complete(cs, guestfd, 0); 289 } 290 unlock_user(p, fname, 0); 291 } 292 293 static void host_close(CPUState *cs, gdb_syscall_complete_cb complete, 294 GuestFD *gf) 295 { 296 /* 297 * Only close the underlying host fd if it's one we opened on behalf 298 * of the guest in SYS_OPEN. 299 */ 300 if (gf->hostfd != STDIN_FILENO && 301 gf->hostfd != STDOUT_FILENO && 302 gf->hostfd != STDERR_FILENO && 303 close(gf->hostfd) < 0) { 304 complete(cs, -1, errno); 305 } else { 306 complete(cs, 0, 0); 307 } 308 } 309 310 static void host_read(CPUState *cs, gdb_syscall_complete_cb complete, 311 GuestFD *gf, target_ulong buf, target_ulong len) 312 { 313 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 314 void *ptr = lock_user(VERIFY_WRITE, buf, len, 0); 315 ssize_t ret; 316 317 if (!ptr) { 318 complete(cs, -1, EFAULT); 319 return; 320 } 321 ret = RETRY_ON_EINTR(read(gf->hostfd, ptr, len)); 322 if (ret == -1) { 323 unlock_user(ptr, buf, 0); 324 complete(cs, -1, errno); 325 } else { 326 unlock_user(ptr, buf, ret); 327 complete(cs, ret, 0); 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 unlock_user(ptr, buf, 0); 344 complete(cs, ret, ret == -1 ? errno : 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 unlock_user(name, fname, 0); 431 complete(cs, ret, err); 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 unlock_user(p, fname, 0); 449 complete(cs, ret, ret ? errno : 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 unlock_user(ostr, oname, 0); 474 unlock_user(nstr, nname, 0); 475 complete(cs, ret, ret ? errno : 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 unlock_user(p, cmd, 0); 493 complete(cs, ret, ret == -1 ? errno : 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 #ifndef CONFIG_USER_ONLY 523 static void host_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, 524 GuestFD *gf, GIOCondition cond, int timeout) 525 { 526 /* 527 * Since this is only used by xtensa in system mode, and stdio is 528 * handled through GuestFDConsole, and there are no semihosting 529 * system calls for sockets and the like, that means this descriptor 530 * must be a normal file. Normal files never block and are thus 531 * always ready. 532 */ 533 complete(cs, cond & (G_IO_IN | G_IO_OUT), 0); 534 } 535 #endif 536 537 /* 538 * Static file semihosting syscall implementations. 539 */ 540 541 static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete, 542 GuestFD *gf, target_ulong buf, target_ulong len) 543 { 544 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 545 target_ulong rest = gf->staticfile.len - gf->staticfile.off; 546 void *ptr; 547 548 if (len > rest) { 549 len = rest; 550 } 551 ptr = lock_user(VERIFY_WRITE, buf, len, 0); 552 if (!ptr) { 553 complete(cs, -1, EFAULT); 554 return; 555 } 556 memcpy(ptr, gf->staticfile.data + gf->staticfile.off, len); 557 gf->staticfile.off += len; 558 unlock_user(ptr, buf, len); 559 complete(cs, len, 0); 560 } 561 562 static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 563 GuestFD *gf, int64_t off, int gdb_whence) 564 { 565 int64_t ret; 566 567 switch (gdb_whence) { 568 case GDB_SEEK_SET: 569 ret = off; 570 break; 571 case GDB_SEEK_CUR: 572 ret = gf->staticfile.off + off; 573 break; 574 case GDB_SEEK_END: 575 ret = gf->staticfile.len + off; 576 break; 577 default: 578 ret = -1; 579 break; 580 } 581 if (ret >= 0 && ret <= gf->staticfile.len) { 582 gf->staticfile.off = ret; 583 complete(cs, ret, 0); 584 } else { 585 complete(cs, -1, EINVAL); 586 } 587 } 588 589 static void staticfile_flen(CPUState *cs, gdb_syscall_complete_cb complete, 590 GuestFD *gf) 591 { 592 complete(cs, gf->staticfile.len, 0); 593 } 594 595 /* 596 * Console semihosting syscall implementations. 597 */ 598 599 static void console_read(CPUState *cs, gdb_syscall_complete_cb complete, 600 GuestFD *gf, target_ulong buf, target_ulong len) 601 { 602 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 603 char *ptr; 604 int ret; 605 606 ptr = lock_user(VERIFY_WRITE, buf, len, 0); 607 if (!ptr) { 608 complete(cs, -1, EFAULT); 609 return; 610 } 611 ret = qemu_semihosting_console_read(cs, ptr, len); 612 unlock_user(ptr, buf, ret); 613 complete(cs, ret, 0); 614 } 615 616 static void console_write(CPUState *cs, gdb_syscall_complete_cb complete, 617 GuestFD *gf, target_ulong buf, target_ulong len) 618 { 619 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 620 char *ptr = lock_user(VERIFY_READ, buf, len, 1); 621 int ret; 622 623 if (!ptr) { 624 complete(cs, -1, EFAULT); 625 return; 626 } 627 ret = qemu_semihosting_console_write(ptr, len); 628 unlock_user(ptr, buf, 0); 629 complete(cs, ret ? ret : -1, ret ? 0 : EIO); 630 } 631 632 static void console_fstat(CPUState *cs, gdb_syscall_complete_cb complete, 633 GuestFD *gf, target_ulong addr) 634 { 635 static const struct stat tty_buf = { 636 .st_mode = 020666, /* S_IFCHR, ugo+rw */ 637 .st_rdev = 5, /* makedev(5, 0) -- linux /dev/tty */ 638 }; 639 int ret; 640 641 ret = copy_stat_to_user(cs, addr, &tty_buf); 642 complete(cs, ret ? -1 : 0, ret ? -ret : 0); 643 } 644 645 #ifndef CONFIG_USER_ONLY 646 static void console_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, 647 GuestFD *gf, GIOCondition cond, int timeout) 648 { 649 /* The semihosting console does not support urgent data or errors. */ 650 cond &= G_IO_IN | G_IO_OUT; 651 652 /* 653 * Since qemu_semihosting_console_write never blocks, we can 654 * consider output always ready -- leave G_IO_OUT alone. 655 * All that remains is to conditionally signal input ready. 656 * Since output ready causes an immediate return, only block 657 * for G_IO_IN alone. 658 * 659 * TODO: Implement proper timeout. For now, only support 660 * indefinite wait or immediate poll. 661 */ 662 if (cond == G_IO_IN && timeout < 0) { 663 qemu_semihosting_console_block_until_ready(cs); 664 /* We returned -- input must be ready. */ 665 } else if ((cond & G_IO_IN) && !qemu_semihosting_console_ready()) { 666 cond &= ~G_IO_IN; 667 } 668 669 complete(cs, cond, 0); 670 } 671 #endif 672 673 /* 674 * Syscall entry points. 675 */ 676 677 void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete, 678 target_ulong fname, target_ulong fname_len, 679 int gdb_flags, int mode) 680 { 681 if (use_gdb_syscalls()) { 682 gdb_open(cs, complete, fname, fname_len, gdb_flags, mode); 683 } else { 684 host_open(cs, complete, fname, fname_len, gdb_flags, mode); 685 } 686 } 687 688 void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete, int fd) 689 { 690 GuestFD *gf = get_guestfd(fd); 691 692 if (!gf) { 693 complete(cs, -1, EBADF); 694 return; 695 } 696 switch (gf->type) { 697 case GuestFDGDB: 698 gdb_close(cs, complete, gf); 699 break; 700 case GuestFDHost: 701 host_close(cs, complete, gf); 702 break; 703 case GuestFDStatic: 704 case GuestFDConsole: 705 complete(cs, 0, 0); 706 break; 707 default: 708 g_assert_not_reached(); 709 } 710 dealloc_guestfd(fd); 711 } 712 713 void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete, 714 GuestFD *gf, target_ulong buf, target_ulong len) 715 { 716 /* 717 * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. 718 * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad 719 * idea to do this unconditionally. 720 */ 721 if (len > INT32_MAX) { 722 len = INT32_MAX; 723 } 724 switch (gf->type) { 725 case GuestFDGDB: 726 gdb_read(cs, complete, gf, buf, len); 727 break; 728 case GuestFDHost: 729 host_read(cs, complete, gf, buf, len); 730 break; 731 case GuestFDStatic: 732 staticfile_read(cs, complete, gf, buf, len); 733 break; 734 case GuestFDConsole: 735 console_read(cs, complete, gf, buf, len); 736 break; 737 default: 738 g_assert_not_reached(); 739 } 740 } 741 742 void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete, 743 int fd, target_ulong buf, target_ulong len) 744 { 745 GuestFD *gf = get_guestfd(fd); 746 747 if (gf) { 748 semihost_sys_read_gf(cs, complete, gf, buf, len); 749 } else { 750 complete(cs, -1, EBADF); 751 } 752 } 753 754 void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete, 755 GuestFD *gf, target_ulong buf, target_ulong len) 756 { 757 /* 758 * Bound length for 64-bit guests on 32-bit hosts, not overlowing ssize_t. 759 * Note the Linux kernel does this with MAX_RW_COUNT, so it's not a bad 760 * idea to do this unconditionally. 761 */ 762 if (len > INT32_MAX) { 763 len = INT32_MAX; 764 } 765 switch (gf->type) { 766 case GuestFDGDB: 767 gdb_write(cs, complete, gf, buf, len); 768 break; 769 case GuestFDHost: 770 host_write(cs, complete, gf, buf, len); 771 break; 772 case GuestFDConsole: 773 console_write(cs, complete, gf, buf, len); 774 break; 775 case GuestFDStatic: 776 /* Static files are never open for writing: EBADF. */ 777 complete(cs, -1, EBADF); 778 break; 779 default: 780 g_assert_not_reached(); 781 } 782 } 783 784 void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete, 785 int fd, target_ulong buf, target_ulong len) 786 { 787 GuestFD *gf = get_guestfd(fd); 788 789 if (gf) { 790 semihost_sys_write_gf(cs, complete, gf, buf, len); 791 } else { 792 complete(cs, -1, EBADF); 793 } 794 } 795 796 void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete, 797 int fd, int64_t off, int gdb_whence) 798 { 799 GuestFD *gf = get_guestfd(fd); 800 801 if (!gf) { 802 complete(cs, -1, EBADF); 803 return; 804 } 805 switch (gf->type) { 806 case GuestFDGDB: 807 gdb_lseek(cs, complete, gf, off, gdb_whence); 808 return; 809 case GuestFDHost: 810 host_lseek(cs, complete, gf, off, gdb_whence); 811 break; 812 case GuestFDStatic: 813 staticfile_lseek(cs, complete, gf, off, gdb_whence); 814 break; 815 case GuestFDConsole: 816 complete(cs, -1, ESPIPE); 817 break; 818 default: 819 g_assert_not_reached(); 820 } 821 } 822 823 void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete, int fd) 824 { 825 GuestFD *gf = get_guestfd(fd); 826 827 if (!gf) { 828 complete(cs, 0, EBADF); 829 return; 830 } 831 switch (gf->type) { 832 case GuestFDGDB: 833 gdb_isatty(cs, complete, gf); 834 break; 835 case GuestFDHost: 836 host_isatty(cs, complete, gf); 837 break; 838 case GuestFDStatic: 839 complete(cs, 0, ENOTTY); 840 break; 841 case GuestFDConsole: 842 complete(cs, 1, 0); 843 break; 844 default: 845 g_assert_not_reached(); 846 } 847 } 848 849 void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb, 850 gdb_syscall_complete_cb flen_cb, int fd, 851 target_ulong fstat_addr) 852 { 853 GuestFD *gf = get_guestfd(fd); 854 855 if (!gf) { 856 flen_cb(cs, -1, EBADF); 857 return; 858 } 859 switch (gf->type) { 860 case GuestFDGDB: 861 gdb_fstat(cs, fstat_cb, gf, fstat_addr); 862 break; 863 case GuestFDHost: 864 host_flen(cs, flen_cb, gf); 865 break; 866 case GuestFDStatic: 867 staticfile_flen(cs, flen_cb, gf); 868 break; 869 case GuestFDConsole: 870 default: 871 g_assert_not_reached(); 872 } 873 } 874 875 void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete, 876 int fd, target_ulong addr) 877 { 878 GuestFD *gf = get_guestfd(fd); 879 880 if (!gf) { 881 complete(cs, -1, EBADF); 882 return; 883 } 884 switch (gf->type) { 885 case GuestFDGDB: 886 gdb_fstat(cs, complete, gf, addr); 887 break; 888 case GuestFDHost: 889 host_fstat(cs, complete, gf, addr); 890 break; 891 case GuestFDConsole: 892 console_fstat(cs, complete, gf, addr); 893 break; 894 case GuestFDStatic: 895 default: 896 g_assert_not_reached(); 897 } 898 } 899 900 void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete, 901 target_ulong fname, target_ulong fname_len, 902 target_ulong addr) 903 { 904 if (use_gdb_syscalls()) { 905 gdb_stat(cs, complete, fname, fname_len, addr); 906 } else { 907 host_stat(cs, complete, fname, fname_len, addr); 908 } 909 } 910 911 void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete, 912 target_ulong fname, target_ulong fname_len) 913 { 914 if (use_gdb_syscalls()) { 915 gdb_remove(cs, complete, fname, fname_len); 916 } else { 917 host_remove(cs, complete, fname, fname_len); 918 } 919 } 920 921 void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete, 922 target_ulong oname, target_ulong oname_len, 923 target_ulong nname, target_ulong nname_len) 924 { 925 if (use_gdb_syscalls()) { 926 gdb_rename(cs, complete, oname, oname_len, nname, nname_len); 927 } else { 928 host_rename(cs, complete, oname, oname_len, nname, nname_len); 929 } 930 } 931 932 void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete, 933 target_ulong cmd, target_ulong cmd_len) 934 { 935 if (use_gdb_syscalls()) { 936 gdb_system(cs, complete, cmd, cmd_len); 937 } else { 938 host_system(cs, complete, cmd, cmd_len); 939 } 940 } 941 942 void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete, 943 target_ulong tv_addr, target_ulong tz_addr) 944 { 945 if (use_gdb_syscalls()) { 946 gdb_gettimeofday(cs, complete, tv_addr, tz_addr); 947 } else { 948 host_gettimeofday(cs, complete, tv_addr, tz_addr); 949 } 950 } 951 952 #ifndef CONFIG_USER_ONLY 953 void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete, 954 int fd, GIOCondition cond, int timeout) 955 { 956 GuestFD *gf = get_guestfd(fd); 957 958 if (!gf) { 959 complete(cs, G_IO_NVAL, 1); 960 return; 961 } 962 switch (gf->type) { 963 case GuestFDGDB: 964 complete(cs, G_IO_NVAL, 1); 965 break; 966 case GuestFDHost: 967 host_poll_one(cs, complete, gf, cond, timeout); 968 break; 969 case GuestFDConsole: 970 console_poll_one(cs, complete, gf, cond, timeout); 971 break; 972 case GuestFDStatic: 973 default: 974 g_assert_not_reached(); 975 } 976 } 977 #endif 978