arm-compat-semi.c (37587B)
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 36#include "semihosting/semihost.h" 37#include "semihosting/console.h" 38#include "semihosting/common-semi.h" 39#include "qemu/timer.h" 40#include "exec/gdbstub.h" 41#ifdef CONFIG_USER_ONLY 42#include "qemu.h" 43 44#define COMMON_SEMI_HEAP_SIZE (128 * 1024 * 1024) 45#else 46#include "qemu/cutils.h" 47#ifdef TARGET_ARM 48#include "hw/arm/boot.h" 49#endif 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#define GDB_O_RDONLY 0x000 88#define GDB_O_WRONLY 0x001 89#define GDB_O_RDWR 0x002 90#define GDB_O_APPEND 0x008 91#define GDB_O_CREAT 0x200 92#define GDB_O_TRUNC 0x400 93#define GDB_O_BINARY 0 94 95static int gdb_open_modeflags[12] = { 96 GDB_O_RDONLY, 97 GDB_O_RDONLY | GDB_O_BINARY, 98 GDB_O_RDWR, 99 GDB_O_RDWR | GDB_O_BINARY, 100 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC, 101 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY, 102 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC, 103 GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY, 104 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND, 105 GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY, 106 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND, 107 GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY 108}; 109 110static int open_modeflags[12] = { 111 O_RDONLY, 112 O_RDONLY | O_BINARY, 113 O_RDWR, 114 O_RDWR | O_BINARY, 115 O_WRONLY | O_CREAT | O_TRUNC, 116 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 117 O_RDWR | O_CREAT | O_TRUNC, 118 O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 119 O_WRONLY | O_CREAT | O_APPEND, 120 O_WRONLY | O_CREAT | O_APPEND | O_BINARY, 121 O_RDWR | O_CREAT | O_APPEND, 122 O_RDWR | O_CREAT | O_APPEND | O_BINARY 123}; 124 125typedef enum GuestFDType { 126 GuestFDUnused = 0, 127 GuestFDHost = 1, 128 GuestFDGDB = 2, 129 GuestFDFeatureFile = 3, 130} GuestFDType; 131 132/* 133 * Guest file descriptors are integer indexes into an array of 134 * these structures (we will dynamically resize as necessary). 135 */ 136typedef struct GuestFD { 137 GuestFDType type; 138 union { 139 int hostfd; 140 target_ulong featurefile_offset; 141 }; 142} GuestFD; 143 144static GArray *guestfd_array; 145 146#ifndef CONFIG_USER_ONLY 147#include "exec/address-spaces.h" 148/* 149 * Find the base of a RAM region containing the specified address 150 */ 151static inline hwaddr 152common_semi_find_region_base(hwaddr addr) 153{ 154 MemoryRegion *subregion; 155 156 /* 157 * Find the chunk of R/W memory containing the address. This is 158 * used for the SYS_HEAPINFO semihosting call, which should 159 * probably be using information from the loaded application. 160 */ 161 QTAILQ_FOREACH(subregion, &get_system_memory()->subregions, 162 subregions_link) { 163 if (subregion->ram && !subregion->readonly) { 164 Int128 top128 = int128_add(int128_make64(subregion->addr), 165 subregion->size); 166 Int128 addr128 = int128_make64(addr); 167 if (subregion->addr <= addr && int128_lt(addr128, top128)) { 168 return subregion->addr; 169 } 170 } 171 } 172 return 0; 173} 174#endif 175 176#ifdef TARGET_ARM 177static inline target_ulong 178common_semi_arg(CPUState *cs, int argno) 179{ 180 ARMCPU *cpu = ARM_CPU(cs); 181 CPUARMState *env = &cpu->env; 182 if (is_a64(env)) { 183 return env->xregs[argno]; 184 } else { 185 return env->regs[argno]; 186 } 187} 188 189static inline void 190common_semi_set_ret(CPUState *cs, target_ulong ret) 191{ 192 ARMCPU *cpu = ARM_CPU(cs); 193 CPUARMState *env = &cpu->env; 194 if (is_a64(env)) { 195 env->xregs[0] = ret; 196 } else { 197 env->regs[0] = ret; 198 } 199} 200 201static inline bool 202common_semi_sys_exit_extended(CPUState *cs, int nr) 203{ 204 return (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(cs->env_ptr)); 205} 206 207#ifndef CONFIG_USER_ONLY 208#include "hw/arm/boot.h" 209static inline target_ulong 210common_semi_rambase(CPUState *cs) 211{ 212 CPUArchState *env = cs->env_ptr; 213 const struct arm_boot_info *info = env->boot_info; 214 target_ulong sp; 215 216 if (info) { 217 return info->loader_start; 218 } 219 220 if (is_a64(env)) { 221 sp = env->xregs[31]; 222 } else { 223 sp = env->regs[13]; 224 } 225 return common_semi_find_region_base(sp); 226} 227#endif 228 229#endif /* TARGET_ARM */ 230 231#ifdef TARGET_RISCV 232static inline target_ulong 233common_semi_arg(CPUState *cs, int argno) 234{ 235 RISCVCPU *cpu = RISCV_CPU(cs); 236 CPURISCVState *env = &cpu->env; 237 return env->gpr[xA0 + argno]; 238} 239 240static inline void 241common_semi_set_ret(CPUState *cs, target_ulong ret) 242{ 243 RISCVCPU *cpu = RISCV_CPU(cs); 244 CPURISCVState *env = &cpu->env; 245 env->gpr[xA0] = ret; 246} 247 248static inline bool 249common_semi_sys_exit_extended(CPUState *cs, int nr) 250{ 251 return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8); 252} 253 254#ifndef CONFIG_USER_ONLY 255 256static inline target_ulong 257common_semi_rambase(CPUState *cs) 258{ 259 RISCVCPU *cpu = RISCV_CPU(cs); 260 CPURISCVState *env = &cpu->env; 261 return common_semi_find_region_base(env->gpr[xSP]); 262} 263#endif 264 265#endif 266 267/* 268 * Allocate a new guest file descriptor and return it; if we 269 * couldn't allocate a new fd then return -1. 270 * This is a fairly simplistic implementation because we don't 271 * expect that most semihosting guest programs will make very 272 * heavy use of opening and closing fds. 273 */ 274static int alloc_guestfd(void) 275{ 276 guint i; 277 278 if (!guestfd_array) { 279 /* New entries zero-initialized, i.e. type GuestFDUnused */ 280 guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD)); 281 } 282 283 /* SYS_OPEN should return nonzero handle on success. Start guestfd from 1 */ 284 for (i = 1; i < guestfd_array->len; i++) { 285 GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i); 286 287 if (gf->type == GuestFDUnused) { 288 return i; 289 } 290 } 291 292 /* All elements already in use: expand the array */ 293 g_array_set_size(guestfd_array, i + 1); 294 return i; 295} 296 297/* 298 * Look up the guestfd in the data structure; return NULL 299 * for out of bounds, but don't check whether the slot is unused. 300 * This is used internally by the other guestfd functions. 301 */ 302static GuestFD *do_get_guestfd(int guestfd) 303{ 304 if (!guestfd_array) { 305 return NULL; 306 } 307 308 if (guestfd <= 0 || guestfd >= guestfd_array->len) { 309 return NULL; 310 } 311 312 return &g_array_index(guestfd_array, GuestFD, guestfd); 313} 314 315/* 316 * Associate the specified guest fd (which must have been 317 * allocated via alloc_fd() and not previously used) with 318 * the specified host/gdb fd. 319 */ 320static void associate_guestfd(int guestfd, int hostfd) 321{ 322 GuestFD *gf = do_get_guestfd(guestfd); 323 324 assert(gf); 325 gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost; 326 gf->hostfd = hostfd; 327} 328 329/* 330 * Deallocate the specified guest file descriptor. This doesn't 331 * close the host fd, it merely undoes the work of alloc_fd(). 332 */ 333static void dealloc_guestfd(int guestfd) 334{ 335 GuestFD *gf = do_get_guestfd(guestfd); 336 337 assert(gf); 338 gf->type = GuestFDUnused; 339} 340 341/* 342 * Given a guest file descriptor, get the associated struct. 343 * If the fd is not valid, return NULL. This is the function 344 * used by the various semihosting calls to validate a handle 345 * from the guest. 346 * Note: calling alloc_guestfd() or dealloc_guestfd() will 347 * invalidate any GuestFD* obtained by calling this function. 348 */ 349static GuestFD *get_guestfd(int guestfd) 350{ 351 GuestFD *gf = do_get_guestfd(guestfd); 352 353 if (!gf || gf->type == GuestFDUnused) { 354 return NULL; 355 } 356 return gf; 357} 358 359/* 360 * The semihosting API has no concept of its errno being thread-safe, 361 * as the API design predates SMP CPUs and was intended as a simple 362 * real-hardware set of debug functionality. For QEMU, we make the 363 * errno be per-thread in linux-user mode; in softmmu it is a simple 364 * global, and we assume that the guest takes care of avoiding any races. 365 */ 366#ifndef CONFIG_USER_ONLY 367static target_ulong syscall_err; 368 369#include "exec/softmmu-semi.h" 370#endif 371 372static inline uint32_t set_swi_errno(CPUState *cs, uint32_t code) 373{ 374 if (code == (uint32_t)-1) { 375#ifdef CONFIG_USER_ONLY 376 TaskState *ts = cs->opaque; 377 378 ts->swi_errno = errno; 379#else 380 syscall_err = errno; 381#endif 382 } 383 return code; 384} 385 386static inline uint32_t get_swi_errno(CPUState *cs) 387{ 388#ifdef CONFIG_USER_ONLY 389 TaskState *ts = cs->opaque; 390 391 return ts->swi_errno; 392#else 393 return syscall_err; 394#endif 395} 396 397static target_ulong common_semi_syscall_len; 398 399static void common_semi_cb(CPUState *cs, target_ulong ret, target_ulong err) 400{ 401 target_ulong reg0 = common_semi_arg(cs, 0); 402 403 if (ret == (target_ulong)-1) { 404 errno = err; 405 set_swi_errno(cs, -1); 406 reg0 = ret; 407 } else { 408 /* Fixup syscalls that use nonstardard return conventions. */ 409 switch (reg0) { 410 case TARGET_SYS_WRITE: 411 case TARGET_SYS_READ: 412 reg0 = common_semi_syscall_len - ret; 413 break; 414 case TARGET_SYS_SEEK: 415 reg0 = 0; 416 break; 417 default: 418 reg0 = ret; 419 break; 420 } 421 } 422 common_semi_set_ret(cs, reg0); 423} 424 425static target_ulong common_semi_flen_buf(CPUState *cs) 426{ 427 target_ulong sp; 428#ifdef TARGET_ARM 429 /* Return an address in target memory of 64 bytes where the remote 430 * gdb should write its stat struct. (The format of this structure 431 * is defined by GDB's remote protocol and is not target-specific.) 432 * We put this on the guest's stack just below SP. 433 */ 434 ARMCPU *cpu = ARM_CPU(cs); 435 CPUARMState *env = &cpu->env; 436 437 if (is_a64(env)) { 438 sp = env->xregs[31]; 439 } else { 440 sp = env->regs[13]; 441 } 442#endif 443#ifdef TARGET_RISCV 444 RISCVCPU *cpu = RISCV_CPU(cs); 445 CPURISCVState *env = &cpu->env; 446 447 sp = env->gpr[xSP]; 448#endif 449 450 return sp - 64; 451} 452 453static void 454common_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err) 455{ 456 /* The size is always stored in big-endian order, extract 457 the value. We assume the size always fit in 32 bits. */ 458 uint32_t size; 459 cpu_memory_rw_debug(cs, common_semi_flen_buf(cs) + 32, 460 (uint8_t *)&size, 4, 0); 461 size = be32_to_cpu(size); 462 common_semi_set_ret(cs, size); 463 errno = err; 464 set_swi_errno(cs, -1); 465} 466 467static int common_semi_open_guestfd; 468 469static void 470common_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err) 471{ 472 if (ret == (target_ulong)-1) { 473 errno = err; 474 set_swi_errno(cs, -1); 475 dealloc_guestfd(common_semi_open_guestfd); 476 } else { 477 associate_guestfd(common_semi_open_guestfd, ret); 478 ret = common_semi_open_guestfd; 479 } 480 common_semi_set_ret(cs, ret); 481} 482 483static target_ulong 484common_semi_gdb_syscall(CPUState *cs, gdb_syscall_complete_cb cb, 485 const char *fmt, ...) 486{ 487 va_list va; 488 489 va_start(va, fmt); 490 gdb_do_syscallv(cb, fmt, va); 491 va_end(va); 492 493 /* 494 * FIXME: in softmmu mode, the gdbstub will schedule our callback 495 * to occur, but will not actually call it to complete the syscall 496 * until after this function has returned and we are back in the 497 * CPU main loop. Therefore callers to this function must not 498 * do anything with its return value, because it is not necessarily 499 * the result of the syscall, but could just be the old value of X0. 500 * The only thing safe to do with this is that the callers of 501 * do_common_semihosting() will write it straight back into X0. 502 * (In linux-user mode, the callback will have happened before 503 * gdb_do_syscallv() returns.) 504 * 505 * We should tidy this up so neither this function nor 506 * do_common_semihosting() return a value, so the mistake of 507 * doing something with the return value is not possible to make. 508 */ 509 510 return common_semi_arg(cs, 0); 511} 512 513/* 514 * Types for functions implementing various semihosting calls 515 * for specific types of guest file descriptor. These must all 516 * do the work and return the required return value for the guest, 517 * setting the guest errno if appropriate. 518 */ 519typedef uint32_t sys_closefn(CPUState *cs, GuestFD *gf); 520typedef uint32_t sys_writefn(CPUState *cs, GuestFD *gf, 521 target_ulong buf, uint32_t len); 522typedef uint32_t sys_readfn(CPUState *cs, GuestFD *gf, 523 target_ulong buf, uint32_t len); 524typedef uint32_t sys_isattyfn(CPUState *cs, GuestFD *gf); 525typedef uint32_t sys_seekfn(CPUState *cs, GuestFD *gf, 526 target_ulong offset); 527typedef uint32_t sys_flenfn(CPUState *cs, GuestFD *gf); 528 529static uint32_t host_closefn(CPUState *cs, GuestFD *gf) 530{ 531 /* 532 * Only close the underlying host fd if it's one we opened on behalf 533 * of the guest in SYS_OPEN. 534 */ 535 if (gf->hostfd == STDIN_FILENO || 536 gf->hostfd == STDOUT_FILENO || 537 gf->hostfd == STDERR_FILENO) { 538 return 0; 539 } 540 return set_swi_errno(cs, close(gf->hostfd)); 541} 542 543static uint32_t host_writefn(CPUState *cs, GuestFD *gf, 544 target_ulong buf, uint32_t len) 545{ 546 CPUArchState *env = cs->env_ptr; 547 uint32_t ret; 548 char *s = lock_user(VERIFY_READ, buf, len, 1); 549 (void) env; /* Used in arm softmmu lock_user implicitly */ 550 if (!s) { 551 /* Return bytes not written on error */ 552 return len; 553 } 554 ret = set_swi_errno(cs, write(gf->hostfd, s, len)); 555 unlock_user(s, buf, 0); 556 if (ret == (uint32_t)-1) { 557 ret = 0; 558 } 559 /* Return bytes not written */ 560 return len - ret; 561} 562 563static uint32_t host_readfn(CPUState *cs, GuestFD *gf, 564 target_ulong buf, uint32_t len) 565{ 566 CPUArchState *env = cs->env_ptr; 567 uint32_t ret; 568 char *s = lock_user(VERIFY_WRITE, buf, len, 0); 569 (void) env; /* Used in arm softmmu lock_user implicitly */ 570 if (!s) { 571 /* return bytes not read */ 572 return len; 573 } 574 do { 575 ret = set_swi_errno(cs, read(gf->hostfd, s, len)); 576 } while (ret == -1 && errno == EINTR); 577 unlock_user(s, buf, len); 578 if (ret == (uint32_t)-1) { 579 ret = 0; 580 } 581 /* Return bytes not read */ 582 return len - ret; 583} 584 585static uint32_t host_isattyfn(CPUState *cs, GuestFD *gf) 586{ 587 return isatty(gf->hostfd); 588} 589 590static uint32_t host_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset) 591{ 592 uint32_t ret = set_swi_errno(cs, lseek(gf->hostfd, offset, SEEK_SET)); 593 if (ret == (uint32_t)-1) { 594 return -1; 595 } 596 return 0; 597} 598 599static uint32_t host_flenfn(CPUState *cs, GuestFD *gf) 600{ 601 struct stat buf; 602 uint32_t ret = set_swi_errno(cs, fstat(gf->hostfd, &buf)); 603 if (ret == (uint32_t)-1) { 604 return -1; 605 } 606 return buf.st_size; 607} 608 609static uint32_t gdb_closefn(CPUState *cs, GuestFD *gf) 610{ 611 return common_semi_gdb_syscall(cs, common_semi_cb, "close,%x", gf->hostfd); 612} 613 614static uint32_t gdb_writefn(CPUState *cs, GuestFD *gf, 615 target_ulong buf, uint32_t len) 616{ 617 common_semi_syscall_len = len; 618 return common_semi_gdb_syscall(cs, common_semi_cb, "write,%x,%x,%x", 619 gf->hostfd, buf, len); 620} 621 622static uint32_t gdb_readfn(CPUState *cs, GuestFD *gf, 623 target_ulong buf, uint32_t len) 624{ 625 common_semi_syscall_len = len; 626 return common_semi_gdb_syscall(cs, common_semi_cb, "read,%x,%x,%x", 627 gf->hostfd, buf, len); 628} 629 630static uint32_t gdb_isattyfn(CPUState *cs, GuestFD *gf) 631{ 632 return common_semi_gdb_syscall(cs, common_semi_cb, "isatty,%x", gf->hostfd); 633} 634 635static uint32_t gdb_seekfn(CPUState *cs, GuestFD *gf, target_ulong offset) 636{ 637 return common_semi_gdb_syscall(cs, common_semi_cb, "lseek,%x,%x,0", 638 gf->hostfd, offset); 639} 640 641static uint32_t gdb_flenfn(CPUState *cs, GuestFD *gf) 642{ 643 return common_semi_gdb_syscall(cs, common_semi_flen_cb, "fstat,%x,%x", 644 gf->hostfd, common_semi_flen_buf(cs)); 645} 646 647#define SHFB_MAGIC_0 0x53 648#define SHFB_MAGIC_1 0x48 649#define SHFB_MAGIC_2 0x46 650#define SHFB_MAGIC_3 0x42 651 652/* Feature bits reportable in feature byte 0 */ 653#define SH_EXT_EXIT_EXTENDED (1 << 0) 654#define SH_EXT_STDOUT_STDERR (1 << 1) 655 656static const uint8_t featurefile_data[] = { 657 SHFB_MAGIC_0, 658 SHFB_MAGIC_1, 659 SHFB_MAGIC_2, 660 SHFB_MAGIC_3, 661 SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */ 662}; 663 664static void init_featurefile_guestfd(int guestfd) 665{ 666 GuestFD *gf = do_get_guestfd(guestfd); 667 668 assert(gf); 669 gf->type = GuestFDFeatureFile; 670 gf->featurefile_offset = 0; 671} 672 673static uint32_t featurefile_closefn(CPUState *cs, GuestFD *gf) 674{ 675 /* Nothing to do */ 676 return 0; 677} 678 679static uint32_t featurefile_writefn(CPUState *cs, GuestFD *gf, 680 target_ulong buf, uint32_t len) 681{ 682 /* This fd can never be open for writing */ 683 684 errno = EBADF; 685 return set_swi_errno(cs, -1); 686} 687 688static uint32_t featurefile_readfn(CPUState *cs, GuestFD *gf, 689 target_ulong buf, uint32_t len) 690{ 691 CPUArchState *env = cs->env_ptr; 692 uint32_t i; 693 char *s; 694 695 (void) env; /* Used in arm softmmu lock_user implicitly */ 696 s = lock_user(VERIFY_WRITE, buf, len, 0); 697 if (!s) { 698 return len; 699 } 700 701 for (i = 0; i < len; i++) { 702 if (gf->featurefile_offset >= sizeof(featurefile_data)) { 703 break; 704 } 705 s[i] = featurefile_data[gf->featurefile_offset]; 706 gf->featurefile_offset++; 707 } 708 709 unlock_user(s, buf, len); 710 711 /* Return number of bytes not read */ 712 return len - i; 713} 714 715static uint32_t featurefile_isattyfn(CPUState *cs, GuestFD *gf) 716{ 717 return 0; 718} 719 720static uint32_t featurefile_seekfn(CPUState *cs, GuestFD *gf, 721 target_ulong offset) 722{ 723 gf->featurefile_offset = offset; 724 return 0; 725} 726 727static uint32_t featurefile_flenfn(CPUState *cs, GuestFD *gf) 728{ 729 return sizeof(featurefile_data); 730} 731 732typedef struct GuestFDFunctions { 733 sys_closefn *closefn; 734 sys_writefn *writefn; 735 sys_readfn *readfn; 736 sys_isattyfn *isattyfn; 737 sys_seekfn *seekfn; 738 sys_flenfn *flenfn; 739} GuestFDFunctions; 740 741static const GuestFDFunctions guestfd_fns[] = { 742 [GuestFDHost] = { 743 .closefn = host_closefn, 744 .writefn = host_writefn, 745 .readfn = host_readfn, 746 .isattyfn = host_isattyfn, 747 .seekfn = host_seekfn, 748 .flenfn = host_flenfn, 749 }, 750 [GuestFDGDB] = { 751 .closefn = gdb_closefn, 752 .writefn = gdb_writefn, 753 .readfn = gdb_readfn, 754 .isattyfn = gdb_isattyfn, 755 .seekfn = gdb_seekfn, 756 .flenfn = gdb_flenfn, 757 }, 758 [GuestFDFeatureFile] = { 759 .closefn = featurefile_closefn, 760 .writefn = featurefile_writefn, 761 .readfn = featurefile_readfn, 762 .isattyfn = featurefile_isattyfn, 763 .seekfn = featurefile_seekfn, 764 .flenfn = featurefile_flenfn, 765 }, 766}; 767 768/* 769 * Read the input value from the argument block; fail the semihosting 770 * call if the memory read fails. Eventually we could use a generic 771 * CPUState helper function here. 772 */ 773static inline bool is_64bit_semihosting(CPUArchState *env) 774{ 775#if defined(TARGET_ARM) 776 return is_a64(env); 777#elif defined(TARGET_RISCV) 778 return !riscv_cpu_is_32bit(env); 779#else 780#error un-handled architecture 781#endif 782} 783 784 785#define GET_ARG(n) do { \ 786 if (is_64bit_semihosting(env)) { \ 787 if (get_user_u64(arg ## n, args + (n) * 8)) { \ 788 errno = EFAULT; \ 789 return set_swi_errno(cs, -1); \ 790 } \ 791 } else { \ 792 if (get_user_u32(arg ## n, args + (n) * 4)) { \ 793 errno = EFAULT; \ 794 return set_swi_errno(cs, -1); \ 795 } \ 796 } \ 797} while (0) 798 799#define SET_ARG(n, val) \ 800 (is_64bit_semihosting(env) ? \ 801 put_user_u64(val, args + (n) * 8) : \ 802 put_user_u32(val, args + (n) * 4)) 803 804 805/* 806 * Do a semihosting call. 807 * 808 * The specification always says that the "return register" either 809 * returns a specific value or is corrupted, so we don't need to 810 * report to our caller whether we are returning a value or trying to 811 * leave the register unchanged. We use 0xdeadbeef as the return value 812 * when there isn't a defined return value for the call. 813 */ 814target_ulong do_common_semihosting(CPUState *cs) 815{ 816 CPUArchState *env = cs->env_ptr; 817 target_ulong args; 818 target_ulong arg0, arg1, arg2, arg3; 819 target_ulong ul_ret; 820 char * s; 821 int nr; 822 uint32_t ret; 823 uint32_t len; 824 GuestFD *gf; 825 int64_t elapsed; 826 827 (void) env; /* Used implicitly by arm lock_user macro */ 828 nr = common_semi_arg(cs, 0) & 0xffffffffU; 829 args = common_semi_arg(cs, 1); 830 831 switch (nr) { 832 case TARGET_SYS_OPEN: 833 { 834 int guestfd; 835 836 GET_ARG(0); 837 GET_ARG(1); 838 GET_ARG(2); 839 s = lock_user_string(arg0); 840 if (!s) { 841 errno = EFAULT; 842 return set_swi_errno(cs, -1); 843 } 844 if (arg1 >= 12) { 845 unlock_user(s, arg0, 0); 846 errno = EINVAL; 847 return set_swi_errno(cs, -1); 848 } 849 850 guestfd = alloc_guestfd(); 851 if (guestfd < 0) { 852 unlock_user(s, arg0, 0); 853 errno = EMFILE; 854 return set_swi_errno(cs, -1); 855 } 856 857 if (strcmp(s, ":tt") == 0) { 858 int result_fileno; 859 860 /* 861 * We implement SH_EXT_STDOUT_STDERR, so: 862 * open for read == stdin 863 * open for write == stdout 864 * open for append == stderr 865 */ 866 if (arg1 < 4) { 867 result_fileno = STDIN_FILENO; 868 } else if (arg1 < 8) { 869 result_fileno = STDOUT_FILENO; 870 } else { 871 result_fileno = STDERR_FILENO; 872 } 873 associate_guestfd(guestfd, result_fileno); 874 unlock_user(s, arg0, 0); 875 return guestfd; 876 } 877 if (strcmp(s, ":semihosting-features") == 0) { 878 unlock_user(s, arg0, 0); 879 /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */ 880 if (arg1 != 0 && arg1 != 1) { 881 dealloc_guestfd(guestfd); 882 errno = EACCES; 883 return set_swi_errno(cs, -1); 884 } 885 init_featurefile_guestfd(guestfd); 886 return guestfd; 887 } 888 889 if (use_gdb_syscalls()) { 890 common_semi_open_guestfd = guestfd; 891 ret = common_semi_gdb_syscall(cs, common_semi_open_cb, 892 "open,%s,%x,1a4", arg0, (int)arg2 + 1, 893 gdb_open_modeflags[arg1]); 894 } else { 895 ret = set_swi_errno(cs, open(s, open_modeflags[arg1], 0644)); 896 if (ret == (uint32_t)-1) { 897 dealloc_guestfd(guestfd); 898 } else { 899 associate_guestfd(guestfd, ret); 900 ret = guestfd; 901 } 902 } 903 unlock_user(s, arg0, 0); 904 return ret; 905 } 906 case TARGET_SYS_CLOSE: 907 GET_ARG(0); 908 909 gf = get_guestfd(arg0); 910 if (!gf) { 911 errno = EBADF; 912 return set_swi_errno(cs, -1); 913 } 914 915 ret = guestfd_fns[gf->type].closefn(cs, gf); 916 dealloc_guestfd(arg0); 917 return ret; 918 case TARGET_SYS_WRITEC: 919 qemu_semihosting_console_outc(cs->env_ptr, args); 920 return 0xdeadbeef; 921 case TARGET_SYS_WRITE0: 922 return qemu_semihosting_console_outs(cs->env_ptr, args); 923 case TARGET_SYS_WRITE: 924 GET_ARG(0); 925 GET_ARG(1); 926 GET_ARG(2); 927 len = arg2; 928 929 gf = get_guestfd(arg0); 930 if (!gf) { 931 errno = EBADF; 932 return set_swi_errno(cs, -1); 933 } 934 935 return guestfd_fns[gf->type].writefn(cs, gf, arg1, len); 936 case TARGET_SYS_READ: 937 GET_ARG(0); 938 GET_ARG(1); 939 GET_ARG(2); 940 len = arg2; 941 942 gf = get_guestfd(arg0); 943 if (!gf) { 944 errno = EBADF; 945 return set_swi_errno(cs, -1); 946 } 947 948 return guestfd_fns[gf->type].readfn(cs, gf, arg1, len); 949 case TARGET_SYS_READC: 950 return qemu_semihosting_console_inc(cs->env_ptr); 951 case TARGET_SYS_ISERROR: 952 GET_ARG(0); 953 return (target_long) arg0 < 0 ? 1 : 0; 954 case TARGET_SYS_ISTTY: 955 GET_ARG(0); 956 957 gf = get_guestfd(arg0); 958 if (!gf) { 959 errno = EBADF; 960 return set_swi_errno(cs, -1); 961 } 962 963 return guestfd_fns[gf->type].isattyfn(cs, gf); 964 case TARGET_SYS_SEEK: 965 GET_ARG(0); 966 GET_ARG(1); 967 968 gf = get_guestfd(arg0); 969 if (!gf) { 970 errno = EBADF; 971 return set_swi_errno(cs, -1); 972 } 973 974 return guestfd_fns[gf->type].seekfn(cs, gf, arg1); 975 case TARGET_SYS_FLEN: 976 GET_ARG(0); 977 978 gf = get_guestfd(arg0); 979 if (!gf) { 980 errno = EBADF; 981 return set_swi_errno(cs, -1); 982 } 983 984 return guestfd_fns[gf->type].flenfn(cs, gf); 985 case TARGET_SYS_TMPNAM: 986 GET_ARG(0); 987 GET_ARG(1); 988 GET_ARG(2); 989 if (asprintf(&s, "/tmp/qemu-%x%02x", getpid(), 990 (int) (arg1 & 0xff)) < 0) { 991 return -1; 992 } 993 ul_ret = (target_ulong) -1; 994 995 /* Make sure there's enough space in the buffer */ 996 if (strlen(s) < arg2) { 997 char *output = lock_user(VERIFY_WRITE, arg0, arg2, 0); 998 strcpy(output, s); 999 unlock_user(output, arg0, arg2); 1000 ul_ret = 0; 1001 } 1002 free(s); 1003 return ul_ret; 1004 case TARGET_SYS_REMOVE: 1005 GET_ARG(0); 1006 GET_ARG(1); 1007 if (use_gdb_syscalls()) { 1008 ret = common_semi_gdb_syscall(cs, common_semi_cb, "unlink,%s", 1009 arg0, (int)arg1 + 1); 1010 } else { 1011 s = lock_user_string(arg0); 1012 if (!s) { 1013 errno = EFAULT; 1014 return set_swi_errno(cs, -1); 1015 } 1016 ret = set_swi_errno(cs, remove(s)); 1017 unlock_user(s, arg0, 0); 1018 } 1019 return ret; 1020 case TARGET_SYS_RENAME: 1021 GET_ARG(0); 1022 GET_ARG(1); 1023 GET_ARG(2); 1024 GET_ARG(3); 1025 if (use_gdb_syscalls()) { 1026 return common_semi_gdb_syscall(cs, common_semi_cb, "rename,%s,%s", 1027 arg0, (int)arg1 + 1, arg2, 1028 (int)arg3 + 1); 1029 } else { 1030 char *s2; 1031 s = lock_user_string(arg0); 1032 s2 = lock_user_string(arg2); 1033 if (!s || !s2) { 1034 errno = EFAULT; 1035 ret = set_swi_errno(cs, -1); 1036 } else { 1037 ret = set_swi_errno(cs, rename(s, s2)); 1038 } 1039 if (s2) 1040 unlock_user(s2, arg2, 0); 1041 if (s) 1042 unlock_user(s, arg0, 0); 1043 return ret; 1044 } 1045 case TARGET_SYS_CLOCK: 1046 return clock() / (CLOCKS_PER_SEC / 100); 1047 case TARGET_SYS_TIME: 1048 return set_swi_errno(cs, time(NULL)); 1049 case TARGET_SYS_SYSTEM: 1050 GET_ARG(0); 1051 GET_ARG(1); 1052 if (use_gdb_syscalls()) { 1053 return common_semi_gdb_syscall(cs, common_semi_cb, "system,%s", 1054 arg0, (int)arg1 + 1); 1055 } else { 1056 s = lock_user_string(arg0); 1057 if (!s) { 1058 errno = EFAULT; 1059 return set_swi_errno(cs, -1); 1060 } 1061 ret = set_swi_errno(cs, system(s)); 1062 unlock_user(s, arg0, 0); 1063 return ret; 1064 } 1065 case TARGET_SYS_ERRNO: 1066 return get_swi_errno(cs); 1067 case TARGET_SYS_GET_CMDLINE: 1068 { 1069 /* Build a command-line from the original argv. 1070 * 1071 * The inputs are: 1072 * * arg0, pointer to a buffer of at least the size 1073 * specified in arg1. 1074 * * arg1, size of the buffer pointed to by arg0 in 1075 * bytes. 1076 * 1077 * The outputs are: 1078 * * arg0, pointer to null-terminated string of the 1079 * command line. 1080 * * arg1, length of the string pointed to by arg0. 1081 */ 1082 1083 char *output_buffer; 1084 size_t input_size; 1085 size_t output_size; 1086 int status = 0; 1087#if !defined(CONFIG_USER_ONLY) 1088 const char *cmdline; 1089#else 1090 TaskState *ts = cs->opaque; 1091#endif 1092 GET_ARG(0); 1093 GET_ARG(1); 1094 input_size = arg1; 1095 /* Compute the size of the output string. */ 1096#if !defined(CONFIG_USER_ONLY) 1097 cmdline = semihosting_get_cmdline(); 1098 if (cmdline == NULL) { 1099 cmdline = ""; /* Default to an empty line. */ 1100 } 1101 output_size = strlen(cmdline) + 1; /* Count terminating 0. */ 1102#else 1103 unsigned int i; 1104 1105 output_size = ts->info->arg_end - ts->info->arg_start; 1106 if (!output_size) { 1107 /* 1108 * We special-case the "empty command line" case (argc==0). 1109 * Just provide the terminating 0. 1110 */ 1111 output_size = 1; 1112 } 1113#endif 1114 1115 if (output_size > input_size) { 1116 /* Not enough space to store command-line arguments. */ 1117 errno = E2BIG; 1118 return set_swi_errno(cs, -1); 1119 } 1120 1121 /* Adjust the command-line length. */ 1122 if (SET_ARG(1, output_size - 1)) { 1123 /* Couldn't write back to argument block */ 1124 errno = EFAULT; 1125 return set_swi_errno(cs, -1); 1126 } 1127 1128 /* Lock the buffer on the ARM side. */ 1129 output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0); 1130 if (!output_buffer) { 1131 errno = EFAULT; 1132 return set_swi_errno(cs, -1); 1133 } 1134 1135 /* Copy the command-line arguments. */ 1136#if !defined(CONFIG_USER_ONLY) 1137 pstrcpy(output_buffer, output_size, cmdline); 1138#else 1139 if (output_size == 1) { 1140 /* Empty command-line. */ 1141 output_buffer[0] = '\0'; 1142 goto out; 1143 } 1144 1145 if (copy_from_user(output_buffer, ts->info->arg_start, 1146 output_size)) { 1147 errno = EFAULT; 1148 status = set_swi_errno(cs, -1); 1149 goto out; 1150 } 1151 1152 /* Separate arguments by white spaces. */ 1153 for (i = 0; i < output_size - 1; i++) { 1154 if (output_buffer[i] == 0) { 1155 output_buffer[i] = ' '; 1156 } 1157 } 1158 out: 1159#endif 1160 /* Unlock the buffer on the ARM side. */ 1161 unlock_user(output_buffer, arg0, output_size); 1162 1163 return status; 1164 } 1165 case TARGET_SYS_HEAPINFO: 1166 { 1167 target_ulong retvals[4]; 1168 target_ulong limit; 1169 int i; 1170#ifdef CONFIG_USER_ONLY 1171 TaskState *ts = cs->opaque; 1172#else 1173 target_ulong rambase = common_semi_rambase(cs); 1174#endif 1175 1176 GET_ARG(0); 1177 1178#ifdef CONFIG_USER_ONLY 1179 /* 1180 * Some C libraries assume the heap immediately follows .bss, so 1181 * allocate it using sbrk. 1182 */ 1183 if (!ts->heap_limit) { 1184 abi_ulong ret; 1185 1186 ts->heap_base = do_brk(0); 1187 limit = ts->heap_base + COMMON_SEMI_HEAP_SIZE; 1188 /* Try a big heap, and reduce the size if that fails. */ 1189 for (;;) { 1190 ret = do_brk(limit); 1191 if (ret >= limit) { 1192 break; 1193 } 1194 limit = (ts->heap_base >> 1) + (limit >> 1); 1195 } 1196 ts->heap_limit = limit; 1197 } 1198 1199 retvals[0] = ts->heap_base; 1200 retvals[1] = ts->heap_limit; 1201 retvals[2] = ts->stack_base; 1202 retvals[3] = 0; /* Stack limit. */ 1203#else 1204 limit = current_machine->ram_size; 1205 /* TODO: Make this use the limit of the loaded application. */ 1206 retvals[0] = rambase + limit / 2; 1207 retvals[1] = rambase + limit; 1208 retvals[2] = rambase + limit; /* Stack base */ 1209 retvals[3] = rambase; /* Stack limit. */ 1210#endif 1211 1212 for (i = 0; i < ARRAY_SIZE(retvals); i++) { 1213 bool fail; 1214 1215 if (is_64bit_semihosting(env)) { 1216 fail = put_user_u64(retvals[i], arg0 + i * 8); 1217 } else { 1218 fail = put_user_u32(retvals[i], arg0 + i * 4); 1219 } 1220 1221 if (fail) { 1222 /* Couldn't write back to argument block */ 1223 errno = EFAULT; 1224 return set_swi_errno(cs, -1); 1225 } 1226 } 1227 return 0; 1228 } 1229 case TARGET_SYS_EXIT: 1230 case TARGET_SYS_EXIT_EXTENDED: 1231 if (common_semi_sys_exit_extended(cs, nr)) { 1232 /* 1233 * The A64 version of SYS_EXIT takes a parameter block, 1234 * so the application-exit type can return a subcode which 1235 * is the exit status code from the application. 1236 * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function 1237 * which allows A32/T32 guests to also provide a status code. 1238 */ 1239 GET_ARG(0); 1240 GET_ARG(1); 1241 1242 if (arg0 == ADP_Stopped_ApplicationExit) { 1243 ret = arg1; 1244 } else { 1245 ret = 1; 1246 } 1247 } else { 1248 /* 1249 * The A32/T32 version of SYS_EXIT specifies only 1250 * Stopped_ApplicationExit as normal exit, but does not 1251 * allow the guest to specify the exit status code. 1252 * Everything else is considered an error. 1253 */ 1254 ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1; 1255 } 1256 gdb_exit(ret); 1257 exit(ret); 1258 case TARGET_SYS_ELAPSED: 1259 elapsed = get_clock() - clock_start; 1260 if (sizeof(target_ulong) == 8) { 1261 SET_ARG(0, elapsed); 1262 } else { 1263 SET_ARG(0, (uint32_t) elapsed); 1264 SET_ARG(1, (uint32_t) (elapsed >> 32)); 1265 } 1266 return 0; 1267 case TARGET_SYS_TICKFREQ: 1268 /* qemu always uses nsec */ 1269 return 1000000000; 1270 case TARGET_SYS_SYNCCACHE: 1271 /* 1272 * Clean the D-cache and invalidate the I-cache for the specified 1273 * virtual address range. This is a nop for us since we don't 1274 * implement caches. This is only present on A64. 1275 */ 1276#ifdef TARGET_ARM 1277 if (is_a64(cs->env_ptr)) { 1278 return 0; 1279 } 1280#endif 1281#ifdef TARGET_RISCV 1282 return 0; 1283#endif 1284 /* fall through -- invalid for A32/T32 */ 1285 default: 1286 fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr); 1287 cpu_dump_state(cs, stderr, 0); 1288 abort(); 1289 } 1290}