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