1 /* 2 * Semihosting support for systems modeled on the Arm "Angel" 3 * semihosting syscalls design. This includes Arm and RISC-V processors 4 * 5 * Copyright (c) 2005, 2007 CodeSourcery. 6 * Copyright (c) 2019 Linaro 7 * Written by Paul Brook. 8 * 9 * Copyright © 2020 by Keith Packard <keithp@keithp.com> 10 * Adapted for systems other than ARM, including RISC-V, by Keith Packard 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, see <http://www.gnu.org/licenses/>. 24 * 25 * ARM Semihosting is documented in: 26 * Semihosting for AArch32 and AArch64 Release 2.0 27 * https://static.docs.arm.com/100863/0200/semihosting.pdf 28 * 29 * RISC-V Semihosting is documented in: 30 * RISC-V Semihosting 31 * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc 32 */ 33 34 #include "qemu/osdep.h" 35 #include "qemu/timer.h" 36 #include "exec/gdbstub.h" 37 #include "semihosting/semihost.h" 38 #include "semihosting/console.h" 39 #include "semihosting/common-semi.h" 40 #include "semihosting/guestfd.h" 41 #include "semihosting/syscalls.h" 42 43 #ifdef CONFIG_USER_ONLY 44 #include "qemu.h" 45 46 #define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024) 47 #else 48 #include "qemu/cutils.h" 49 #include "hw/loader.h" 50 #include "hw/boards.h" 51 #endif 52 53 #define TARGET_SYS_OPEN 0x01 54 #define TARGET_SYS_CLOSE 0x02 55 #define TARGET_SYS_WRITEC 0x03 56 #define TARGET_SYS_WRITE0 0x04 57 #define TARGET_SYS_WRITE 0x05 58 #define TARGET_SYS_READ 0x06 59 #define TARGET_SYS_READC 0x07 60 #define TARGET_SYS_ISERROR 0x08 61 #define TARGET_SYS_ISTTY 0x09 62 #define TARGET_SYS_SEEK 0x0a 63 #define TARGET_SYS_FLEN 0x0c 64 #define TARGET_SYS_TMPNAM 0x0d 65 #define TARGET_SYS_REMOVE 0x0e 66 #define TARGET_SYS_RENAME 0x0f 67 #define TARGET_SYS_CLOCK 0x10 68 #define TARGET_SYS_TIME 0x11 69 #define TARGET_SYS_SYSTEM 0x12 70 #define TARGET_SYS_ERRNO 0x13 71 #define TARGET_SYS_GET_CMDLINE 0x15 72 #define TARGET_SYS_HEAPINFO 0x16 73 #define TARGET_SYS_EXIT 0x18 74 #define TARGET_SYS_SYNCCACHE 0x19 75 #define TARGET_SYS_EXIT_EXTENDED 0x20 76 #define TARGET_SYS_ELAPSED 0x30 77 #define TARGET_SYS_TICKFREQ 0x31 78 79 /* ADP_Stopped_ApplicationExit is used for exit(0), 80 * anything else is implemented as exit(1) */ 81 #define ADP_Stopped_ApplicationExit (0x20026) 82 83 #ifndef O_BINARY 84 #define O_BINARY 0 85 #endif 86 87 static int gdb_open_modeflags[12] = { 88 GDB_O_RDONLY, 89 GDB_O_RDONLY, 90 GDB_O_RDWR, 91 GDB_O_RDWR, 92 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, 93 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, 94 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, 95 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, 96 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, 97 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, 98 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, 99 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, 100 }; 101 102 #ifndef CONFIG_USER_ONLY 103 104 /** 105 * common_semi_find_bases: find information about ram and heap base 106 * 107 * This function attempts to provide meaningful numbers for RAM and 108 * HEAP base addresses. The rambase is simply the lowest addressable 109 * RAM position. For the heapbase we ask the loader to scan the 110 * address space and the largest available gap by querying the "ROM" 111 * regions. 112 * 113 * Returns: a structure with the numbers we need. 114 */ 115 116 typedef struct LayoutInfo { 117 target_ulong rambase; 118 size_t ramsize; 119 hwaddr heapbase; 120 hwaddr heaplimit; 121 } LayoutInfo; 122 123 static bool find_ram_cb(Int128 start, Int128 len, const MemoryRegion *mr, 124 hwaddr offset_in_region, void *opaque) 125 { 126 LayoutInfo *info = (LayoutInfo *) opaque; 127 uint64_t size = int128_get64(len); 128 129 if (!mr->ram || mr->readonly) { 130 return false; 131 } 132 133 if (size > info->ramsize) { 134 info->rambase = int128_get64(start); 135 info->ramsize = size; 136 } 137 138 /* search exhaustively for largest RAM */ 139 return false; 140 } 141 142 static LayoutInfo common_semi_find_bases(CPUState *cs) 143 { 144 FlatView *fv; 145 LayoutInfo info = { 0, 0, 0, 0 }; 146 147 RCU_READ_LOCK_GUARD(); 148 149 fv = address_space_to_flatview(cs->as); 150 flatview_for_each_range(fv, find_ram_cb, &info); 151 152 /* 153 * If we have found the RAM lets iterate through the ROM blobs to 154 * work out the best place for the remainder of RAM and split it 155 * equally between stack and heap. 156 */ 157 if (info.rambase || info.ramsize > 0) { 158 RomGap gap = rom_find_largest_gap_between(info.rambase, info.ramsize); 159 info.heapbase = gap.base; 160 info.heaplimit = gap.base + gap.size; 161 } 162 163 return info; 164 } 165 166 #endif 167 168 #include "common-semi-target.h" 169 170 /* 171 * Read the input value from the argument block; fail the semihosting 172 * call if the memory read fails. Eventually we could use a generic 173 * CPUState helper function here. 174 */ 175 176 #define GET_ARG(n) do { \ 177 if (is_64bit_semihosting(env)) { \ 178 if (get_user_u64(arg ## n, args + (n) * 8)) { \ 179 goto do_fault; \ 180 } \ 181 } else { \ 182 if (get_user_u32(arg ## n, args + (n) * 4)) { \ 183 goto do_fault; \ 184 } \ 185 } \ 186 } while (0) 187 188 #define SET_ARG(n, val) \ 189 (is_64bit_semihosting(env) ? \ 190 put_user_u64(val, args + (n) * 8) : \ 191 put_user_u32(val, args + (n) * 4)) 192 193 194 /* 195 * The semihosting API has no concept of its errno being thread-safe, 196 * as the API design predates SMP CPUs and was intended as a simple 197 * real-hardware set of debug functionality. For QEMU, we make the 198 * errno be per-thread in linux-user mode; in softmmu it is a simple 199 * global, and we assume that the guest takes care of avoiding any races. 200 */ 201 #ifndef CONFIG_USER_ONLY 202 static target_ulong syscall_err; 203 204 #include "semihosting/softmmu-uaccess.h" 205 #endif 206 207 static inline uint32_t get_swi_errno(CPUState *cs) 208 { 209 #ifdef CONFIG_USER_ONLY 210 TaskState *ts = cs->opaque; 211 212 return ts->swi_errno; 213 #else 214 return syscall_err; 215 #endif 216 } 217 218 static void common_semi_cb(CPUState *cs, uint64_t ret, int err) 219 { 220 if (err) { 221 #ifdef CONFIG_USER_ONLY 222 TaskState *ts = cs->opaque; 223 ts->swi_errno = err; 224 #else 225 syscall_err = err; 226 #endif 227 } 228 common_semi_set_ret(cs, ret); 229 } 230 231 /* 232 * Use 0xdeadbeef as the return value when there isn't a defined 233 * return value for the call. 234 */ 235 static void common_semi_dead_cb(CPUState *cs, uint64_t ret, int err) 236 { 237 common_semi_set_ret(cs, 0xdeadbeef); 238 } 239 240 /* 241 * SYS_READ and SYS_WRITE always return the number of bytes not read/written. 242 * There is no error condition, other than returning the original length. 243 */ 244 static void common_semi_rw_cb(CPUState *cs, uint64_t ret, int err) 245 { 246 /* Recover the original length from the third argument. */ 247 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 248 target_ulong args = common_semi_arg(cs, 1); 249 target_ulong arg2; 250 GET_ARG(2); 251 252 if (err) { 253 do_fault: 254 ret = 0; /* error: no bytes transmitted */ 255 } 256 common_semi_set_ret(cs, arg2 - ret); 257 } 258 259 /* 260 * Convert from Posix ret+errno to Arm SYS_ISTTY return values. 261 * With gdbstub, err is only ever set for protocol errors to EIO. 262 */ 263 static void common_semi_istty_cb(CPUState *cs, uint64_t ret, int err) 264 { 265 if (err) { 266 ret = (err == ENOTTY ? 0 : -1); 267 } 268 common_semi_cb(cs, ret, err); 269 } 270 271 /* 272 * SYS_SEEK returns 0 on success, not the resulting offset. 273 */ 274 static void common_semi_seek_cb(CPUState *cs, uint64_t ret, int err) 275 { 276 if (!err) { 277 ret = 0; 278 } 279 common_semi_cb(cs, ret, err); 280 } 281 282 /* 283 * Return an address in target memory of 64 bytes where the remote 284 * gdb should write its stat struct. (The format of this structure 285 * is defined by GDB's remote protocol and is not target-specific.) 286 * We put this on the guest's stack just below SP. 287 */ 288 static target_ulong common_semi_flen_buf(CPUState *cs) 289 { 290 target_ulong sp = common_semi_stack_bottom(cs); 291 return sp - 64; 292 } 293 294 static void 295 common_semi_flen_fstat_cb(CPUState *cs, uint64_t ret, int err) 296 { 297 if (!err) { 298 /* The size is always stored in big-endian order, extract the value. */ 299 uint64_t size; 300 if (cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 301 offsetof(struct gdb_stat, gdb_st_size), 302 &size, 8, 0)) { 303 ret = -1, err = EFAULT; 304 } else { 305 size = be64_to_cpu(size); 306 if (ret != size) { 307 ret = -1, err = EOVERFLOW; 308 } 309 } 310 } 311 common_semi_cb(cs, ret, err); 312 } 313 314 static void 315 common_semi_readc_cb(CPUState *cs, uint64_t ret, int err) 316 { 317 if (!err) { 318 CPUArchState *env G_GNUC_UNUSED = cs->env_ptr; 319 uint8_t ch; 320 321 if (get_user_u8(ch, common_semi_stack_bottom(cs) - 1)) { 322 ret = -1, err = EFAULT; 323 } else { 324 ret = ch; 325 } 326 } 327 common_semi_cb(cs, ret, err); 328 } 329 330 #define SHFB_MAGIC_0 0x53 331 #define SHFB_MAGIC_1 0x48 332 #define SHFB_MAGIC_2 0x46 333 #define SHFB_MAGIC_3 0x42 334 335 /* Feature bits reportable in feature byte 0 */ 336 #define SH_EXT_EXIT_EXTENDED (1 << 0) 337 #define SH_EXT_STDOUT_STDERR (1 << 1) 338 339 static const uint8_t featurefile_data[] = { 340 SHFB_MAGIC_0, 341 SHFB_MAGIC_1, 342 SHFB_MAGIC_2, 343 SHFB_MAGIC_3, 344 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */ 345 }; 346 347 /* 348 * Do a semihosting call. 349 * 350 * The specification always says that the "return register" either 351 * returns a specific value or is corrupted, so we don't need to 352 * report to our caller whether we are returning a value or trying to 353 * leave the register unchanged. 354 */ 355 void do_common_semihosting(CPUState *cs) 356 { 357 CPUArchState *env = cs->env_ptr; 358 target_ulong args; 359 target_ulong arg0, arg1, arg2, arg3; 360 target_ulong ul_ret; 361 char * s; 362 int nr; 363 uint32_t ret; 364 int64_t elapsed; 365 366 nr = common_semi_arg(cs, 0) & 0xffffffffU; 367 args = common_semi_arg(cs, 1); 368 369 switch (nr) { 370 case TARGET_SYS_OPEN: 371 { 372 int ret, err = 0; 373 int hostfd; 374 375 GET_ARG(0); 376 GET_ARG(1); 377 GET_ARG(2); 378 s = lock_user_string(arg0); 379 if (!s) { 380 goto do_fault; 381 } 382 if (arg1 >= 12) { 383 unlock_user(s, arg0, 0); 384 common_semi_cb(cs, -1, EINVAL); 385 break; 386 } 387 388 if (strcmp(s, ":tt") == 0) { 389 /* 390 * We implement SH_EXT_STDOUT_STDERR, so: 391 * open for read == stdin 392 * open for write == stdout 393 * open for append == stderr 394 */ 395 if (arg1 < 4) { 396 hostfd = STDIN_FILENO; 397 } else if (arg1 < 8) { 398 hostfd = STDOUT_FILENO; 399 } else { 400 hostfd = STDERR_FILENO; 401 } 402 ret = alloc_guestfd(); 403 associate_guestfd(ret, hostfd); 404 } else if (strcmp(s, ":semihosting-features") == 0) { 405 /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ 406 if (arg1 != 0 && arg1 != 1) { 407 ret = -1; 408 err = EACCES; 409 } else { 410 ret = alloc_guestfd(); 411 staticfile_guestfd(ret, featurefile_data, 412 sizeof(featurefile_data)); 413 } 414 } else { 415 unlock_user(s, arg0, 0); 416 semihost_sys_open(cs, common_semi_cb, arg0, arg2 + 1, 417 gdb_open_modeflags[arg1], 0644); 418 break; 419 } 420 unlock_user(s, arg0, 0); 421 common_semi_cb(cs, ret, err); 422 break; 423 } 424 425 case TARGET_SYS_CLOSE: 426 GET_ARG(0); 427 semihost_sys_close(cs, common_semi_cb, arg0); 428 break; 429 430 case TARGET_SYS_WRITEC: 431 /* 432 * FIXME: the byte to be written is in a target_ulong slot, 433 * which means this is wrong for a big-endian guest. 434 */ 435 semihost_sys_write_gf(cs, common_semi_dead_cb, 436 &console_out_gf, args, 1); 437 break; 438 439 case TARGET_SYS_WRITE0: 440 { 441 ssize_t len = target_strlen(args); 442 if (len < 0) { 443 common_semi_dead_cb(cs, -1, EFAULT); 444 } else { 445 semihost_sys_write_gf(cs, common_semi_dead_cb, 446 &console_out_gf, args, len); 447 } 448 } 449 break; 450 451 case TARGET_SYS_WRITE: 452 GET_ARG(0); 453 GET_ARG(1); 454 GET_ARG(2); 455 semihost_sys_write(cs, common_semi_rw_cb, arg0, arg1, arg2); 456 break; 457 458 case TARGET_SYS_READ: 459 GET_ARG(0); 460 GET_ARG(1); 461 GET_ARG(2); 462 semihost_sys_read(cs, common_semi_rw_cb, arg0, arg1, arg2); 463 break; 464 465 case TARGET_SYS_READC: 466 semihost_sys_read_gf(cs, common_semi_readc_cb, &console_in_gf, 467 common_semi_stack_bottom(cs) - 1, 1); 468 break; 469 470 case TARGET_SYS_ISERROR: 471 GET_ARG(0); 472 common_semi_set_ret(cs, (target_long)arg0 < 0); 473 break; 474 475 case TARGET_SYS_ISTTY: 476 GET_ARG(0); 477 semihost_sys_isatty(cs, common_semi_istty_cb, arg0); 478 break; 479 480 case TARGET_SYS_SEEK: 481 GET_ARG(0); 482 GET_ARG(1); 483 semihost_sys_lseek(cs, common_semi_seek_cb, arg0, arg1, GDB_SEEK_SET); 484 break; 485 486 case TARGET_SYS_FLEN: 487 GET_ARG(0); 488 semihost_sys_flen(cs, common_semi_flen_fstat_cb, common_semi_cb, 489 arg0, common_semi_flen_buf(cs)); 490 break; 491 492 case TARGET_SYS_TMPNAM: 493 { 494 int len; 495 char *p; 496 497 GET_ARG(0); 498 GET_ARG(1); 499 GET_ARG(2); 500 len = asprintf(&s, "/tmp/qemu-%x%02x", getpid(), (int)arg1 & 0xff); 501 /* Make sure there's enough space in the buffer */ 502 if (len < 0 || len >= arg2) { 503 common_semi_set_ret(cs, -1); 504 break; 505 } 506 p = lock_user(VERIFY_WRITE, arg0, len, 0); 507 if (!p) { 508 goto do_fault; 509 } 510 memcpy(p, s, len + 1); 511 unlock_user(p, arg0, len); 512 free(s); 513 common_semi_set_ret(cs, 0); 514 break; 515 } 516 517 case TARGET_SYS_REMOVE: 518 GET_ARG(0); 519 GET_ARG(1); 520 semihost_sys_remove(cs, common_semi_cb, arg0, arg1 + 1); 521 break; 522 523 case TARGET_SYS_RENAME: 524 GET_ARG(0); 525 GET_ARG(1); 526 GET_ARG(2); 527 GET_ARG(3); 528 semihost_sys_rename(cs, common_semi_cb, arg0, arg1 + 1, arg2, arg3 + 1); 529 break; 530 531 case TARGET_SYS_CLOCK: 532 common_semi_set_ret(cs, clock() / (CLOCKS_PER_SEC / 100)); 533 break; 534 535 case TARGET_SYS_TIME: 536 ul_ret = time(NULL); 537 common_semi_cb(cs, ul_ret, ul_ret == -1 ? errno : 0); 538 break; 539 540 case TARGET_SYS_SYSTEM: 541 GET_ARG(0); 542 GET_ARG(1); 543 semihost_sys_system(cs, common_semi_cb, arg0, arg1 + 1); 544 break; 545 546 case TARGET_SYS_ERRNO: 547 common_semi_set_ret(cs, get_swi_errno(cs)); 548 break; 549 550 case TARGET_SYS_GET_CMDLINE: 551 { 552 /* Build a command-line from the original argv. 553 * 554 * The inputs are: 555 * * arg0, pointer to a buffer of at least the size 556 * specified in arg1. 557 * * arg1, size of the buffer pointed to by arg0 in 558 * bytes. 559 * 560 * The outputs are: 561 * * arg0, pointer to null-terminated string of the 562 * command line. 563 * * arg1, length of the string pointed to by arg0. 564 */ 565 566 char *output_buffer; 567 size_t input_size; 568 size_t output_size; 569 int status = 0; 570 #if !defined(CONFIG_USER_ONLY) 571 const char *cmdline; 572 #else 573 TaskState *ts = cs->opaque; 574 #endif 575 GET_ARG(0); 576 GET_ARG(1); 577 input_size = arg1; 578 /* Compute the size of the output string. */ 579 #if !defined(CONFIG_USER_ONLY) 580 cmdline = semihosting_get_cmdline(); 581 if (cmdline == NULL) { 582 cmdline = ""; /* Default to an empty line. */ 583 } 584 output_size = strlen(cmdline) + 1; /* Count terminating 0. */ 585 #else 586 unsigned int i; 587 588 output_size = ts->info->env_strings - ts->info->arg_strings; 589 if (!output_size) { 590 /* 591 * We special-case the "empty command line" case (argc==0). 592 * Just provide the terminating 0. 593 */ 594 output_size = 1; 595 } 596 #endif 597 598 if (output_size > input_size) { 599 /* Not enough space to store command-line arguments. */ 600 common_semi_cb(cs, -1, E2BIG); 601 break; 602 } 603 604 /* Adjust the command-line length. */ 605 if (SET_ARG(1, output_size - 1)) { 606 /* Couldn't write back to argument block */ 607 goto do_fault; 608 } 609 610 /* Lock the buffer on the ARM side. */ 611 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0); 612 if (!output_buffer) { 613 goto do_fault; 614 } 615 616 /* Copy the command-line arguments. */ 617 #if !defined(CONFIG_USER_ONLY) 618 pstrcpy(output_buffer, output_size, cmdline); 619 #else 620 if (output_size == 1) { 621 /* Empty command-line. */ 622 output_buffer[0] = '\0'; 623 goto out; 624 } 625 626 if (copy_from_user(output_buffer, ts->info->arg_strings, 627 output_size)) { 628 unlock_user(output_buffer, arg0, 0); 629 goto do_fault; 630 } 631 632 /* Separate arguments by white spaces. */ 633 for (i = 0; i < output_size - 1; i++) { 634 if (output_buffer[i] == 0) { 635 output_buffer[i] = ' '; 636 } 637 } 638 out: 639 #endif 640 /* Unlock the buffer on the ARM side. */ 641 unlock_user(output_buffer, arg0, output_size); 642 common_semi_cb(cs, status, 0); 643 } 644 break; 645 646 case TARGET_SYS_HEAPINFO: 647 { 648 target_ulong retvals[4]; 649 int i; 650 #ifdef CONFIG_USER_ONLY 651 TaskState *ts = cs->opaque; 652 target_ulong limit; 653 #else 654 LayoutInfo info = common_semi_find_bases(cs); 655 #endif 656 657 GET_ARG(0); 658 659 #ifdef CONFIG_USER_ONLY 660 /* 661 * Some C libraries assume the heap immediately follows .bss, so 662 * allocate it using sbrk. 663 */ 664 if (!ts->heap_limit) { 665 abi_ulong ret; 666 667 ts->heap_base = do_brk(0); 668 limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE; 669 /* Try a big heap, and reduce the size if that fails. */ 670 for (;;) { 671 ret = do_brk(limit); 672 if (ret >= limit) { 673 break; 674 } 675 limit = (ts->heap_base >> 1) + (limit >> 1); 676 } 677 ts->heap_limit = limit; 678 } 679 680 retvals[0] = ts->heap_base; 681 retvals[1] = ts->heap_limit; 682 retvals[2] = ts->stack_base; 683 retvals[3] = 0; /* Stack limit. */ 684 #else 685 retvals[0] = info.heapbase; /* Heap Base */ 686 retvals[1] = info.heaplimit; /* Heap Limit */ 687 retvals[2] = info.heaplimit; /* Stack base */ 688 retvals[3] = info.heapbase; /* Stack limit. */ 689 #endif 690 691 for (i = 0; i < ARRAY_SIZE(retvals); i++) { 692 bool fail; 693 694 if (is_64bit_semihosting(env)) { 695 fail = put_user_u64(retvals[i], arg0 + i * 8); 696 } else { 697 fail = put_user_u32(retvals[i], arg0 + i * 4); 698 } 699 700 if (fail) { 701 /* Couldn't write back to argument block */ 702 goto do_fault; 703 } 704 } 705 common_semi_set_ret(cs, 0); 706 } 707 break; 708 709 case TARGET_SYS_EXIT: 710 case TARGET_SYS_EXIT_EXTENDED: 711 if (common_semi_sys_exit_extended(cs, nr)) { 712 /* 713 * The A64 version of SYS_EXIT takes a parameter block, 714 * so the application-exit type can return a subcode which 715 * is the exit status code from the application. 716 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function 717 * which allows A32/T32 guests to also provide a status code. 718 */ 719 GET_ARG(0); 720 GET_ARG(1); 721 722 if (arg0 == ADP_Stopped_ApplicationExit) { 723 ret = arg1; 724 } else { 725 ret = 1; 726 } 727 } else { 728 /* 729 * The A32/T32 version of SYS_EXIT specifies only 730 * Stopped_ApplicationExit as normal exit, but does not 731 * allow the guest to specify the exit status code. 732 * Everything else is considered an error. 733 */ 734 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1; 735 } 736 gdb_exit(ret); 737 exit(ret); 738 739 case TARGET_SYS_ELAPSED: 740 elapsed = get_clock() - clock_start; 741 if (sizeof(target_ulong) == 8) { 742 SET_ARG(0, elapsed); 743 } else { 744 SET_ARG(0, (uint32_t) elapsed); 745 SET_ARG(1, (uint32_t) (elapsed >> 32)); 746 } 747 common_semi_set_ret(cs, 0); 748 break; 749 750 case TARGET_SYS_TICKFREQ: 751 /* qemu always uses nsec */ 752 common_semi_set_ret(cs, 1000000000); 753 break; 754 755 case TARGET_SYS_SYNCCACHE: 756 /* 757 * Clean the D-cache and invalidate the I-cache for the specified 758 * virtual address range. This is a nop for us since we don't 759 * implement caches. This is only present on A64. 760 */ 761 if (common_semi_has_synccache(env)) { 762 common_semi_set_ret(cs, 0); 763 break; 764 } 765 /* fall through */ 766 default: 767 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); 768 cpu_dump_state(cs, stderr, 0); 769 abort(); 770 771 do_fault: 772 common_semi_cb(cs, -1, EFAULT); 773 break; 774 } 775 } 776