qemu/target/arm/arm-semi.c
<<
>>
Prefs
   1/*
   2 *  Arm "Angel" semihosting syscalls
   3 *
   4 *  Copyright (c) 2005, 2007 CodeSourcery.
   5 *  Copyright (c) 2019 Linaro
   6 *  Written by Paul Brook.
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *  GNU General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License
  19 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  20 *
  21 *  ARM Semihosting is documented in:
  22 *     Semihosting for AArch32 and AArch64 Release 2.0
  23 *     https://static.docs.arm.com/100863/0200/semihosting.pdf
  24 */
  25
  26#include "qemu/osdep.h"
  27
  28#include "cpu.h"
  29#include "hw/semihosting/semihost.h"
  30#include "hw/semihosting/console.h"
  31#include "qemu/log.h"
  32#ifdef CONFIG_USER_ONLY
  33#include "qemu.h"
  34
  35#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
  36#else
  37#include "exec/gdbstub.h"
  38#include "qemu/cutils.h"
  39#endif
  40
  41#define TARGET_SYS_OPEN        0x01
  42#define TARGET_SYS_CLOSE       0x02
  43#define TARGET_SYS_WRITEC      0x03
  44#define TARGET_SYS_WRITE0      0x04
  45#define TARGET_SYS_WRITE       0x05
  46#define TARGET_SYS_READ        0x06
  47#define TARGET_SYS_READC       0x07
  48#define TARGET_SYS_ISTTY       0x09
  49#define TARGET_SYS_SEEK        0x0a
  50#define TARGET_SYS_FLEN        0x0c
  51#define TARGET_SYS_TMPNAM      0x0d
  52#define TARGET_SYS_REMOVE      0x0e
  53#define TARGET_SYS_RENAME      0x0f
  54#define TARGET_SYS_CLOCK       0x10
  55#define TARGET_SYS_TIME        0x11
  56#define TARGET_SYS_SYSTEM      0x12
  57#define TARGET_SYS_ERRNO       0x13
  58#define TARGET_SYS_GET_CMDLINE 0x15
  59#define TARGET_SYS_HEAPINFO    0x16
  60#define TARGET_SYS_EXIT        0x18
  61#define TARGET_SYS_SYNCCACHE   0x19
  62#define TARGET_SYS_EXIT_EXTENDED 0x20
  63
  64/* ADP_Stopped_ApplicationExit is used for exit(0),
  65 * anything else is implemented as exit(1) */
  66#define ADP_Stopped_ApplicationExit     (0x20026)
  67
  68#ifndef O_BINARY
  69#define O_BINARY 0
  70#endif
  71
  72#define GDB_O_RDONLY  0x000
  73#define GDB_O_WRONLY  0x001
  74#define GDB_O_RDWR    0x002
  75#define GDB_O_APPEND  0x008
  76#define GDB_O_CREAT   0x200
  77#define GDB_O_TRUNC   0x400
  78#define GDB_O_BINARY  0
  79
  80static int gdb_open_modeflags[12] = {
  81    GDB_O_RDONLY,
  82    GDB_O_RDONLY | GDB_O_BINARY,
  83    GDB_O_RDWR,
  84    GDB_O_RDWR | GDB_O_BINARY,
  85    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
  86    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
  87    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
  88    GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
  89    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
  90    GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
  91    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
  92    GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
  93};
  94
  95static int open_modeflags[12] = {
  96    O_RDONLY,
  97    O_RDONLY | O_BINARY,
  98    O_RDWR,
  99    O_RDWR | O_BINARY,
 100    O_WRONLY | O_CREAT | O_TRUNC,
 101    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
 102    O_RDWR | O_CREAT | O_TRUNC,
 103    O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
 104    O_WRONLY | O_CREAT | O_APPEND,
 105    O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
 106    O_RDWR | O_CREAT | O_APPEND,
 107    O_RDWR | O_CREAT | O_APPEND | O_BINARY
 108};
 109
 110typedef enum GuestFDType {
 111    GuestFDUnused = 0,
 112    GuestFDHost = 1,
 113    GuestFDGDB = 2,
 114    GuestFDFeatureFile = 3,
 115} GuestFDType;
 116
 117/*
 118 * Guest file descriptors are integer indexes into an array of
 119 * these structures (we will dynamically resize as necessary).
 120 */
 121typedef struct GuestFD {
 122    GuestFDType type;
 123    union {
 124        int hostfd;
 125        target_ulong featurefile_offset;
 126    };
 127} GuestFD;
 128
 129static GArray *guestfd_array;
 130
 131/*
 132 * Allocate a new guest file descriptor and return it; if we
 133 * couldn't allocate a new fd then return -1.
 134 * This is a fairly simplistic implementation because we don't
 135 * expect that most semihosting guest programs will make very
 136 * heavy use of opening and closing fds.
 137 */
 138static int alloc_guestfd(void)
 139{
 140    guint i;
 141
 142    if (!guestfd_array) {
 143        /* New entries zero-initialized, i.e. type GuestFDUnused */
 144        guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
 145    }
 146
 147    for (i = 0; i < guestfd_array->len; i++) {
 148        GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
 149
 150        if (gf->type == GuestFDUnused) {
 151            return i;
 152        }
 153    }
 154
 155    /* All elements already in use: expand the array */
 156    g_array_set_size(guestfd_array, i + 1);
 157    return i;
 158}
 159
 160/*
 161 * Look up the guestfd in the data structure; return NULL
 162 * for out of bounds, but don't check whether the slot is unused.
 163 * This is used internally by the other guestfd functions.
 164 */
 165static GuestFD *do_get_guestfd(int guestfd)
 166{
 167    if (!guestfd_array) {
 168        return NULL;
 169    }
 170
 171    if (guestfd < 0 || guestfd >= guestfd_array->len) {
 172        return NULL;
 173    }
 174
 175    return &g_array_index(guestfd_array, GuestFD, guestfd);
 176}
 177
 178/*
 179 * Associate the specified guest fd (which must have been
 180 * allocated via alloc_fd() and not previously used) with
 181 * the specified host/gdb fd.
 182 */
 183static void associate_guestfd(int guestfd, int hostfd)
 184{
 185    GuestFD *gf = do_get_guestfd(guestfd);
 186
 187    assert(gf);
 188    gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
 189    gf->hostfd = hostfd;
 190}
 191
 192/*
 193 * Deallocate the specified guest file descriptor. This doesn't
 194 * close the host fd, it merely undoes the work of alloc_fd().
 195 */
 196static void dealloc_guestfd(int guestfd)
 197{
 198    GuestFD *gf = do_get_guestfd(guestfd);
 199
 200    assert(gf);
 201    gf->type = GuestFDUnused;
 202}
 203
 204/*
 205 * Given a guest file descriptor, get the associated struct.
 206 * If the fd is not valid, return NULL. This is the function
 207 * used by the various semihosting calls to validate a handle
 208 * from the guest.
 209 * Note: calling alloc_guestfd() or dealloc_guestfd() will
 210 * invalidate any GuestFD* obtained by calling this function.
 211 */
 212static GuestFD *get_guestfd(int guestfd)
 213{
 214    GuestFD *gf = do_get_guestfd(guestfd);
 215
 216    if (!gf || gf->type == GuestFDUnused) {
 217        return NULL;
 218    }
 219    return gf;
 220}
 221
 222/*
 223 * The semihosting API has no concept of its errno being thread-safe,
 224 * as the API design predates SMP CPUs and was intended as a simple
 225 * real-hardware set of debug functionality. For QEMU, we make the
 226 * errno be per-thread in linux-user mode; in softmmu it is a simple
 227 * global, and we assume that the guest takes care of avoiding any races.
 228 */
 229#ifndef CONFIG_USER_ONLY
 230static target_ulong syscall_err;
 231
 232#include "exec/softmmu-semi.h"
 233#endif
 234
 235static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
 236{
 237    if (code == (uint32_t)-1) {
 238#ifdef CONFIG_USER_ONLY
 239        CPUState *cs = env_cpu(env);
 240        TaskState *ts = cs->opaque;
 241
 242        ts->swi_errno = errno;
 243#else
 244        syscall_err = errno;
 245#endif
 246    }
 247    return code;
 248}
 249
 250static inline uint32_t get_swi_errno(CPUARMState *env)
 251{
 252#ifdef CONFIG_USER_ONLY
 253    CPUState *cs = env_cpu(env);
 254    TaskState *ts = cs->opaque;
 255
 256    return ts->swi_errno;
 257#else
 258    return syscall_err;
 259#endif
 260}
 261
 262static target_ulong arm_semi_syscall_len;
 263
 264static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
 265{
 266    ARMCPU *cpu = ARM_CPU(cs);
 267    CPUARMState *env = &cpu->env;
 268    target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
 269
 270    if (ret == (target_ulong)-1) {
 271        errno = err;
 272        set_swi_errno(env, -1);
 273        reg0 = ret;
 274    } else {
 275        /* Fixup syscalls that use nonstardard return conventions.  */
 276        switch (reg0) {
 277        case TARGET_SYS_WRITE:
 278        case TARGET_SYS_READ:
 279            reg0 = arm_semi_syscall_len - ret;
 280            break;
 281        case TARGET_SYS_SEEK:
 282            reg0 = 0;
 283            break;
 284        default:
 285            reg0 = ret;
 286            break;
 287        }
 288    }
 289    if (is_a64(env)) {
 290        env->xregs[0] = reg0;
 291    } else {
 292        env->regs[0] = reg0;
 293    }
 294}
 295
 296static target_ulong arm_flen_buf(ARMCPU *cpu)
 297{
 298    /* Return an address in target memory of 64 bytes where the remote
 299     * gdb should write its stat struct. (The format of this structure
 300     * is defined by GDB's remote protocol and is not target-specific.)
 301     * We put this on the guest's stack just below SP.
 302     */
 303    CPUARMState *env = &cpu->env;
 304    target_ulong sp;
 305
 306    if (is_a64(env)) {
 307        sp = env->xregs[31];
 308    } else {
 309        sp = env->regs[13];
 310    }
 311
 312    return sp - 64;
 313}
 314
 315static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
 316{
 317    ARMCPU *cpu = ARM_CPU(cs);
 318    CPUARMState *env = &cpu->env;
 319    /* The size is always stored in big-endian order, extract
 320       the value. We assume the size always fit in 32 bits.  */
 321    uint32_t size;
 322    cpu_memory_rw_debug(cs, arm_flen_buf(cpu) + 32, (uint8_t *)&size, 4, 0);
 323    size = be32_to_cpu(size);
 324    if (is_a64(env)) {
 325        env->xregs[0] = size;
 326    } else {
 327        env->regs[0] = size;
 328    }
 329    errno = err;
 330    set_swi_errno(env, -1);
 331}
 332
 333static int arm_semi_open_guestfd;
 334
 335static void arm_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
 336{
 337    ARMCPU *cpu = ARM_CPU(cs);
 338    CPUARMState *env = &cpu->env;
 339    if (ret == (target_ulong)-1) {
 340        errno = err;
 341        set_swi_errno(env, -1);
 342        dealloc_guestfd(arm_semi_open_guestfd);
 343    } else {
 344        associate_guestfd(arm_semi_open_guestfd, ret);
 345        ret = arm_semi_open_guestfd;
 346    }
 347
 348    if (is_a64(env)) {
 349        env->xregs[0] = ret;
 350    } else {
 351        env->regs[0] = ret;
 352    }
 353}
 354
 355static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
 356                                    const char *fmt, ...)
 357{
 358    va_list va;
 359    CPUARMState *env = &cpu->env;
 360
 361    va_start(va, fmt);
 362    gdb_do_syscallv(cb, fmt, va);
 363    va_end(va);
 364
 365    /*
 366     * FIXME: in softmmu mode, the gdbstub will schedule our callback
 367     * to occur, but will not actually call it to complete the syscall
 368     * until after this function has returned and we are back in the
 369     * CPU main loop. Therefore callers to this function must not
 370     * do anything with its return value, because it is not necessarily
 371     * the result of the syscall, but could just be the old value of X0.
 372     * The only thing safe to do with this is that the callers of
 373     * do_arm_semihosting() will write it straight back into X0.
 374     * (In linux-user mode, the callback will have happened before
 375     * gdb_do_syscallv() returns.)
 376     *
 377     * We should tidy this up so neither this function nor
 378     * do_arm_semihosting() return a value, so the mistake of
 379     * doing something with the return value is not possible to make.
 380     */
 381
 382    return is_a64(env) ? env->xregs[0] : env->regs[0];
 383}
 384
 385/*
 386 * Types for functions implementing various semihosting calls
 387 * for specific types of guest file descriptor. These must all
 388 * do the work and return the required return value for the guest,
 389 * setting the guest errno if appropriate.
 390 */
 391typedef uint32_t sys_closefn(ARMCPU *cpu, GuestFD *gf);
 392typedef uint32_t sys_writefn(ARMCPU *cpu, GuestFD *gf,
 393                             target_ulong buf, uint32_t len);
 394typedef uint32_t sys_readfn(ARMCPU *cpu, GuestFD *gf,
 395                            target_ulong buf, uint32_t len);
 396typedef uint32_t sys_isattyfn(ARMCPU *cpu, GuestFD *gf);
 397typedef uint32_t sys_seekfn(ARMCPU *cpu, GuestFD *gf,
 398                            target_ulong offset);
 399typedef uint32_t sys_flenfn(ARMCPU *cpu, GuestFD *gf);
 400
 401static uint32_t host_closefn(ARMCPU *cpu, GuestFD *gf)
 402{
 403    CPUARMState *env = &cpu->env;
 404
 405    return set_swi_errno(env, close(gf->hostfd));
 406}
 407
 408static uint32_t host_writefn(ARMCPU *cpu, GuestFD *gf,
 409                             target_ulong buf, uint32_t len)
 410{
 411    uint32_t ret;
 412    CPUARMState *env = &cpu->env;
 413    char *s = lock_user(VERIFY_READ, buf, len, 1);
 414    if (!s) {
 415        /* Return bytes not written on error */
 416        return len;
 417    }
 418    ret = set_swi_errno(env, write(gf->hostfd, s, len));
 419    unlock_user(s, buf, 0);
 420    if (ret == (uint32_t)-1) {
 421        ret = 0;
 422    }
 423    /* Return bytes not written */
 424    return len - ret;
 425}
 426
 427static uint32_t host_readfn(ARMCPU *cpu, GuestFD *gf,
 428                            target_ulong buf, uint32_t len)
 429{
 430    uint32_t ret;
 431    CPUARMState *env = &cpu->env;
 432    char *s = lock_user(VERIFY_WRITE, buf, len, 0);
 433    if (!s) {
 434        /* return bytes not read */
 435        return len;
 436    }
 437    do {
 438        ret = set_swi_errno(env, read(gf->hostfd, s, len));
 439    } while (ret == -1 && errno == EINTR);
 440    unlock_user(s, buf, len);
 441    if (ret == (uint32_t)-1) {
 442        ret = 0;
 443    }
 444    /* Return bytes not read */
 445    return len - ret;
 446}
 447
 448static uint32_t host_isattyfn(ARMCPU *cpu, GuestFD *gf)
 449{
 450    return isatty(gf->hostfd);
 451}
 452
 453static uint32_t host_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
 454{
 455    CPUARMState *env = &cpu->env;
 456    uint32_t ret = set_swi_errno(env, lseek(gf->hostfd, offset, SEEK_SET));
 457    if (ret == (uint32_t)-1) {
 458        return -1;
 459    }
 460    return 0;
 461}
 462
 463static uint32_t host_flenfn(ARMCPU *cpu, GuestFD *gf)
 464{
 465    CPUARMState *env = &cpu->env;
 466    struct stat buf;
 467    uint32_t ret = set_swi_errno(env, fstat(gf->hostfd, &buf));
 468    if (ret == (uint32_t)-1) {
 469        return -1;
 470    }
 471    return buf.st_size;
 472}
 473
 474static uint32_t gdb_closefn(ARMCPU *cpu, GuestFD *gf)
 475{
 476    return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd);
 477}
 478
 479static uint32_t gdb_writefn(ARMCPU *cpu, GuestFD *gf,
 480                            target_ulong buf, uint32_t len)
 481{
 482    arm_semi_syscall_len = len;
 483    return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
 484                           gf->hostfd, buf, len);
 485}
 486
 487static uint32_t gdb_readfn(ARMCPU *cpu, GuestFD *gf,
 488                           target_ulong buf, uint32_t len)
 489{
 490    arm_semi_syscall_len = len;
 491    return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
 492                           gf->hostfd, buf, len);
 493}
 494
 495static uint32_t gdb_isattyfn(ARMCPU *cpu, GuestFD *gf)
 496{
 497    return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", gf->hostfd);
 498}
 499
 500static uint32_t gdb_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
 501{
 502    return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
 503                           gf->hostfd, offset);
 504}
 505
 506static uint32_t gdb_flenfn(ARMCPU *cpu, GuestFD *gf)
 507{
 508    return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
 509                           gf->hostfd, arm_flen_buf(cpu));
 510}
 511
 512#define SHFB_MAGIC_0 0x53
 513#define SHFB_MAGIC_1 0x48
 514#define SHFB_MAGIC_2 0x46
 515#define SHFB_MAGIC_3 0x42
 516
 517/* Feature bits reportable in feature byte 0 */
 518#define SH_EXT_EXIT_EXTENDED (1 << 0)
 519#define SH_EXT_STDOUT_STDERR (1 << 1)
 520
 521static const uint8_t featurefile_data[] = {
 522    SHFB_MAGIC_0,
 523    SHFB_MAGIC_1,
 524    SHFB_MAGIC_2,
 525    SHFB_MAGIC_3,
 526    SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
 527};
 528
 529static void init_featurefile_guestfd(int guestfd)
 530{
 531    GuestFD *gf = do_get_guestfd(guestfd);
 532
 533    assert(gf);
 534    gf->type = GuestFDFeatureFile;
 535    gf->featurefile_offset = 0;
 536}
 537
 538static uint32_t featurefile_closefn(ARMCPU *cpu, GuestFD *gf)
 539{
 540    /* Nothing to do */
 541    return 0;
 542}
 543
 544static uint32_t featurefile_writefn(ARMCPU *cpu, GuestFD *gf,
 545                                    target_ulong buf, uint32_t len)
 546{
 547    /* This fd can never be open for writing */
 548    CPUARMState *env = &cpu->env;
 549
 550    errno = EBADF;
 551    return set_swi_errno(env, -1);
 552}
 553
 554static uint32_t featurefile_readfn(ARMCPU *cpu, GuestFD *gf,
 555                                   target_ulong buf, uint32_t len)
 556{
 557    uint32_t i;
 558#ifndef CONFIG_USER_ONLY
 559    CPUARMState *env = &cpu->env;
 560#endif
 561    char *s;
 562
 563    s = lock_user(VERIFY_WRITE, buf, len, 0);
 564    if (!s) {
 565        return len;
 566    }
 567
 568    for (i = 0; i < len; i++) {
 569        if (gf->featurefile_offset >= sizeof(featurefile_data)) {
 570            break;
 571        }
 572        s[i] = featurefile_data[gf->featurefile_offset];
 573        gf->featurefile_offset++;
 574    }
 575
 576    unlock_user(s, buf, len);
 577
 578    /* Return number of bytes not read */
 579    return len - i;
 580}
 581
 582static uint32_t featurefile_isattyfn(ARMCPU *cpu, GuestFD *gf)
 583{
 584    return 0;
 585}
 586
 587static uint32_t featurefile_seekfn(ARMCPU *cpu, GuestFD *gf,
 588                                   target_ulong offset)
 589{
 590    gf->featurefile_offset = offset;
 591    return 0;
 592}
 593
 594static uint32_t featurefile_flenfn(ARMCPU *cpu, GuestFD *gf)
 595{
 596    return sizeof(featurefile_data);
 597}
 598
 599typedef struct GuestFDFunctions {
 600    sys_closefn *closefn;
 601    sys_writefn *writefn;
 602    sys_readfn *readfn;
 603    sys_isattyfn *isattyfn;
 604    sys_seekfn *seekfn;
 605    sys_flenfn *flenfn;
 606} GuestFDFunctions;
 607
 608static const GuestFDFunctions guestfd_fns[] = {
 609    [GuestFDHost] = {
 610        .closefn = host_closefn,
 611        .writefn = host_writefn,
 612        .readfn = host_readfn,
 613        .isattyfn = host_isattyfn,
 614        .seekfn = host_seekfn,
 615        .flenfn = host_flenfn,
 616    },
 617    [GuestFDGDB] = {
 618        .closefn = gdb_closefn,
 619        .writefn = gdb_writefn,
 620        .readfn = gdb_readfn,
 621        .isattyfn = gdb_isattyfn,
 622        .seekfn = gdb_seekfn,
 623        .flenfn = gdb_flenfn,
 624    },
 625    [GuestFDFeatureFile] = {
 626        .closefn = featurefile_closefn,
 627        .writefn = featurefile_writefn,
 628        .readfn = featurefile_readfn,
 629        .isattyfn = featurefile_isattyfn,
 630        .seekfn = featurefile_seekfn,
 631        .flenfn = featurefile_flenfn,
 632    },
 633};
 634
 635/* Read the input value from the argument block; fail the semihosting
 636 * call if the memory read fails.
 637 */
 638#define GET_ARG(n) do {                                 \
 639    if (is_a64(env)) {                                  \
 640        if (get_user_u64(arg ## n, args + (n) * 8)) {   \
 641            errno = EFAULT;                             \
 642            return set_swi_errno(env, -1);              \
 643        }                                               \
 644    } else {                                            \
 645        if (get_user_u32(arg ## n, args + (n) * 4)) {   \
 646            errno = EFAULT;                             \
 647            return set_swi_errno(env, -1);              \
 648        }                                               \
 649    }                                                   \
 650} while (0)
 651
 652#define SET_ARG(n, val)                                 \
 653    (is_a64(env) ?                                      \
 654     put_user_u64(val, args + (n) * 8) :                \
 655     put_user_u32(val, args + (n) * 4))
 656
 657/*
 658 * Do a semihosting call.
 659 *
 660 * The specification always says that the "return register" either
 661 * returns a specific value or is corrupted, so we don't need to
 662 * report to our caller whether we are returning a value or trying to
 663 * leave the register unchanged. We use 0xdeadbeef as the return value
 664 * when there isn't a defined return value for the call.
 665 */
 666target_ulong do_arm_semihosting(CPUARMState *env)
 667{
 668    ARMCPU *cpu = env_archcpu(env);
 669    CPUState *cs = env_cpu(env);
 670    target_ulong args;
 671    target_ulong arg0, arg1, arg2, arg3;
 672    char * s;
 673    int nr;
 674    uint32_t ret;
 675    uint32_t len;
 676    GuestFD *gf;
 677
 678    if (is_a64(env)) {
 679        /* Note that the syscall number is in W0, not X0 */
 680        nr = env->xregs[0] & 0xffffffffU;
 681        args = env->xregs[1];
 682    } else {
 683        nr = env->regs[0];
 684        args = env->regs[1];
 685    }
 686
 687    switch (nr) {
 688    case TARGET_SYS_OPEN:
 689    {
 690        int guestfd;
 691
 692        GET_ARG(0);
 693        GET_ARG(1);
 694        GET_ARG(2);
 695        s = lock_user_string(arg0);
 696        if (!s) {
 697            errno = EFAULT;
 698            return set_swi_errno(env, -1);
 699        }
 700        if (arg1 >= 12) {
 701            unlock_user(s, arg0, 0);
 702            errno = EINVAL;
 703            return set_swi_errno(env, -1);
 704        }
 705
 706        guestfd = alloc_guestfd();
 707        if (guestfd < 0) {
 708            unlock_user(s, arg0, 0);
 709            errno = EMFILE;
 710            return set_swi_errno(env, -1);
 711        }
 712
 713        if (strcmp(s, ":tt") == 0) {
 714            int result_fileno;
 715
 716            /*
 717             * We implement SH_EXT_STDOUT_STDERR, so:
 718             *  open for read == stdin
 719             *  open for write == stdout
 720             *  open for append == stderr
 721             */
 722            if (arg1 < 4) {
 723                result_fileno = STDIN_FILENO;
 724            } else if (arg1 < 8) {
 725                result_fileno = STDOUT_FILENO;
 726            } else {
 727                result_fileno = STDERR_FILENO;
 728            }
 729            associate_guestfd(guestfd, result_fileno);
 730            unlock_user(s, arg0, 0);
 731            return guestfd;
 732        }
 733        if (strcmp(s, ":semihosting-features") == 0) {
 734            unlock_user(s, arg0, 0);
 735            /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
 736            if (arg1 != 0 && arg1 != 1) {
 737                dealloc_guestfd(guestfd);
 738                errno = EACCES;
 739                return set_swi_errno(env, -1);
 740            }
 741            init_featurefile_guestfd(guestfd);
 742            return guestfd;
 743        }
 744
 745        if (use_gdb_syscalls()) {
 746            arm_semi_open_guestfd = guestfd;
 747            ret = arm_gdb_syscall(cpu, arm_semi_open_cb, "open,%s,%x,1a4", arg0,
 748                                  (int)arg2+1, gdb_open_modeflags[arg1]);
 749        } else {
 750            ret = set_swi_errno(env, open(s, open_modeflags[arg1], 0644));
 751            if (ret == (uint32_t)-1) {
 752                dealloc_guestfd(guestfd);
 753            } else {
 754                associate_guestfd(guestfd, ret);
 755                ret = guestfd;
 756            }
 757        }
 758        unlock_user(s, arg0, 0);
 759        return ret;
 760    }
 761    case TARGET_SYS_CLOSE:
 762        GET_ARG(0);
 763
 764        gf = get_guestfd(arg0);
 765        if (!gf) {
 766            errno = EBADF;
 767            return set_swi_errno(env, -1);
 768        }
 769
 770        ret = guestfd_fns[gf->type].closefn(cpu, gf);
 771        dealloc_guestfd(arg0);
 772        return ret;
 773    case TARGET_SYS_WRITEC:
 774        qemu_semihosting_console_outc(env, args);
 775        return 0xdeadbeef;
 776    case TARGET_SYS_WRITE0:
 777        return qemu_semihosting_console_outs(env, args);
 778    case TARGET_SYS_WRITE:
 779        GET_ARG(0);
 780        GET_ARG(1);
 781        GET_ARG(2);
 782        len = arg2;
 783
 784        gf = get_guestfd(arg0);
 785        if (!gf) {
 786            errno = EBADF;
 787            return set_swi_errno(env, -1);
 788        }
 789
 790        return guestfd_fns[gf->type].writefn(cpu, gf, arg1, len);
 791    case TARGET_SYS_READ:
 792        GET_ARG(0);
 793        GET_ARG(1);
 794        GET_ARG(2);
 795        len = arg2;
 796
 797        gf = get_guestfd(arg0);
 798        if (!gf) {
 799            errno = EBADF;
 800            return set_swi_errno(env, -1);
 801        }
 802
 803        return guestfd_fns[gf->type].readfn(cpu, gf, arg1, len);
 804    case TARGET_SYS_READC:
 805        qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
 806        return 0;
 807    case TARGET_SYS_ISTTY:
 808        GET_ARG(0);
 809
 810        gf = get_guestfd(arg0);
 811        if (!gf) {
 812            errno = EBADF;
 813            return set_swi_errno(env, -1);
 814        }
 815
 816        return guestfd_fns[gf->type].isattyfn(cpu, gf);
 817    case TARGET_SYS_SEEK:
 818        GET_ARG(0);
 819        GET_ARG(1);
 820
 821        gf = get_guestfd(arg0);
 822        if (!gf) {
 823            errno = EBADF;
 824            return set_swi_errno(env, -1);
 825        }
 826
 827        return guestfd_fns[gf->type].seekfn(cpu, gf, arg1);
 828    case TARGET_SYS_FLEN:
 829        GET_ARG(0);
 830
 831        gf = get_guestfd(arg0);
 832        if (!gf) {
 833            errno = EBADF;
 834            return set_swi_errno(env, -1);
 835        }
 836
 837        return guestfd_fns[gf->type].flenfn(cpu, gf);
 838    case TARGET_SYS_TMPNAM:
 839        qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
 840        return -1;
 841    case TARGET_SYS_REMOVE:
 842        GET_ARG(0);
 843        GET_ARG(1);
 844        if (use_gdb_syscalls()) {
 845            ret = arm_gdb_syscall(cpu, arm_semi_cb, "unlink,%s",
 846                                  arg0, (int)arg1+1);
 847        } else {
 848            s = lock_user_string(arg0);
 849            if (!s) {
 850                errno = EFAULT;
 851                return set_swi_errno(env, -1);
 852            }
 853            ret =  set_swi_errno(env, remove(s));
 854            unlock_user(s, arg0, 0);
 855        }
 856        return ret;
 857    case TARGET_SYS_RENAME:
 858        GET_ARG(0);
 859        GET_ARG(1);
 860        GET_ARG(2);
 861        GET_ARG(3);
 862        if (use_gdb_syscalls()) {
 863            return arm_gdb_syscall(cpu, arm_semi_cb, "rename,%s,%s",
 864                                   arg0, (int)arg1+1, arg2, (int)arg3+1);
 865        } else {
 866            char *s2;
 867            s = lock_user_string(arg0);
 868            s2 = lock_user_string(arg2);
 869            if (!s || !s2) {
 870                errno = EFAULT;
 871                ret = set_swi_errno(env, -1);
 872            } else {
 873                ret = set_swi_errno(env, rename(s, s2));
 874            }
 875            if (s2)
 876                unlock_user(s2, arg2, 0);
 877            if (s)
 878                unlock_user(s, arg0, 0);
 879            return ret;
 880        }
 881    case TARGET_SYS_CLOCK:
 882        return clock() / (CLOCKS_PER_SEC / 100);
 883    case TARGET_SYS_TIME:
 884        return set_swi_errno(env, time(NULL));
 885    case TARGET_SYS_SYSTEM:
 886        GET_ARG(0);
 887        GET_ARG(1);
 888        if (use_gdb_syscalls()) {
 889            return arm_gdb_syscall(cpu, arm_semi_cb, "system,%s",
 890                                   arg0, (int)arg1+1);
 891        } else {
 892            s = lock_user_string(arg0);
 893            if (!s) {
 894                errno = EFAULT;
 895                return set_swi_errno(env, -1);
 896            }
 897            ret = set_swi_errno(env, system(s));
 898            unlock_user(s, arg0, 0);
 899            return ret;
 900        }
 901    case TARGET_SYS_ERRNO:
 902        return get_swi_errno(env);
 903    case TARGET_SYS_GET_CMDLINE:
 904        {
 905            /* Build a command-line from the original argv.
 906             *
 907             * The inputs are:
 908             *     * arg0, pointer to a buffer of at least the size
 909             *               specified in arg1.
 910             *     * arg1, size of the buffer pointed to by arg0 in
 911             *               bytes.
 912             *
 913             * The outputs are:
 914             *     * arg0, pointer to null-terminated string of the
 915             *               command line.
 916             *     * arg1, length of the string pointed to by arg0.
 917             */
 918
 919            char *output_buffer;
 920            size_t input_size;
 921            size_t output_size;
 922            int status = 0;
 923#if !defined(CONFIG_USER_ONLY)
 924            const char *cmdline;
 925#else
 926            TaskState *ts = cs->opaque;
 927#endif
 928            GET_ARG(0);
 929            GET_ARG(1);
 930            input_size = arg1;
 931            /* Compute the size of the output string.  */
 932#if !defined(CONFIG_USER_ONLY)
 933            cmdline = semihosting_get_cmdline();
 934            if (cmdline == NULL) {
 935                cmdline = ""; /* Default to an empty line. */
 936            }
 937            output_size = strlen(cmdline) + 1; /* Count terminating 0. */
 938#else
 939            unsigned int i;
 940
 941            output_size = ts->info->arg_end - ts->info->arg_start;
 942            if (!output_size) {
 943                /*
 944                 * We special-case the "empty command line" case (argc==0).
 945                 * Just provide the terminating 0.
 946                 */
 947                output_size = 1;
 948            }
 949#endif
 950
 951            if (output_size > input_size) {
 952                /* Not enough space to store command-line arguments.  */
 953                errno = E2BIG;
 954                return set_swi_errno(env, -1);
 955            }
 956
 957            /* Adjust the command-line length.  */
 958            if (SET_ARG(1, output_size - 1)) {
 959                /* Couldn't write back to argument block */
 960                errno = EFAULT;
 961                return set_swi_errno(env, -1);
 962            }
 963
 964            /* Lock the buffer on the ARM side.  */
 965            output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
 966            if (!output_buffer) {
 967                errno = EFAULT;
 968                return set_swi_errno(env, -1);
 969            }
 970
 971            /* Copy the command-line arguments.  */
 972#if !defined(CONFIG_USER_ONLY)
 973            pstrcpy(output_buffer, output_size, cmdline);
 974#else
 975            if (output_size == 1) {
 976                /* Empty command-line.  */
 977                output_buffer[0] = '\0';
 978                goto out;
 979            }
 980
 981            if (copy_from_user(output_buffer, ts->info->arg_start,
 982                               output_size)) {
 983                errno = EFAULT;
 984                status = set_swi_errno(env, -1);
 985                goto out;
 986            }
 987
 988            /* Separate arguments by white spaces.  */
 989            for (i = 0; i < output_size - 1; i++) {
 990                if (output_buffer[i] == 0) {
 991                    output_buffer[i] = ' ';
 992                }
 993            }
 994        out:
 995#endif
 996            /* Unlock the buffer on the ARM side.  */
 997            unlock_user(output_buffer, arg0, output_size);
 998
 999            return status;
1000        }
1001    case TARGET_SYS_HEAPINFO:
1002        {
1003            target_ulong retvals[4];
1004            target_ulong limit;
1005            int i;
1006#ifdef CONFIG_USER_ONLY
1007            TaskState *ts = cs->opaque;
1008#endif
1009
1010            GET_ARG(0);
1011
1012#ifdef CONFIG_USER_ONLY
1013            /*
1014             * Some C libraries assume the heap immediately follows .bss, so
1015             * allocate it using sbrk.
1016             */
1017            if (!ts->heap_limit) {
1018                abi_ulong ret;
1019
1020                ts->heap_base = do_brk(0);
1021                limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
1022                /* Try a big heap, and reduce the size if that fails.  */
1023                for (;;) {
1024                    ret = do_brk(limit);
1025                    if (ret >= limit) {
1026                        break;
1027                    }
1028                    limit = (ts->heap_base >> 1) + (limit >> 1);
1029                }
1030                ts->heap_limit = limit;
1031            }
1032
1033            retvals[0] = ts->heap_base;
1034            retvals[1] = ts->heap_limit;
1035            retvals[2] = ts->stack_base;
1036            retvals[3] = 0; /* Stack limit.  */
1037#else
1038            limit = ram_size;
1039            /* TODO: Make this use the limit of the loaded application.  */
1040            retvals[0] = limit / 2;
1041            retvals[1] = limit;
1042            retvals[2] = limit; /* Stack base */
1043            retvals[3] = 0; /* Stack limit.  */
1044#endif
1045
1046            for (i = 0; i < ARRAY_SIZE(retvals); i++) {
1047                bool fail;
1048
1049                if (is_a64(env)) {
1050                    fail = put_user_u64(retvals[i], arg0 + i * 8);
1051                } else {
1052                    fail = put_user_u32(retvals[i], arg0 + i * 4);
1053                }
1054
1055                if (fail) {
1056                    /* Couldn't write back to argument block */
1057                    errno = EFAULT;
1058                    return set_swi_errno(env, -1);
1059                }
1060            }
1061            return 0;
1062        }
1063    case TARGET_SYS_EXIT:
1064    case TARGET_SYS_EXIT_EXTENDED:
1065        if (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(env)) {
1066            /*
1067             * The A64 version of SYS_EXIT takes a parameter block,
1068             * so the application-exit type can return a subcode which
1069             * is the exit status code from the application.
1070             * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
1071             * which allows A32/T32 guests to also provide a status code.
1072             */
1073            GET_ARG(0);
1074            GET_ARG(1);
1075
1076            if (arg0 == ADP_Stopped_ApplicationExit) {
1077                ret = arg1;
1078            } else {
1079                ret = 1;
1080            }
1081        } else {
1082            /*
1083             * The A32/T32 version of SYS_EXIT specifies only
1084             * Stopped_ApplicationExit as normal exit, but does not
1085             * allow the guest to specify the exit status code.
1086             * Everything else is considered an error.
1087             */
1088            ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
1089        }
1090        gdb_exit(env, ret);
1091        exit(ret);
1092    case TARGET_SYS_SYNCCACHE:
1093        /*
1094         * Clean the D-cache and invalidate the I-cache for the specified
1095         * virtual address range. This is a nop for us since we don't
1096         * implement caches. This is only present on A64.
1097         */
1098        if (is_a64(env)) {
1099            return 0;
1100        }
1101        /* fall through -- invalid for A32/T32 */
1102    default:
1103        fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
1104        cpu_dump_state(cs, stderr, 0);
1105        abort();
1106    }
1107}
1108