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