qemu/linux-user/arm/cpu_loop.c
<<
>>
Prefs
   1/*
   2 *  qemu user cpu loop
   3 *
   4 *  Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu-common.h"
  22#include "qemu.h"
  23#include "user-internals.h"
  24#include "elf.h"
  25#include "cpu_loop-common.h"
  26#include "signal-common.h"
  27#include "semihosting/common-semi.h"
  28#include "target/arm/syndrome.h"
  29
  30#define get_user_code_u32(x, gaddr, env)                \
  31    ({ abi_long __r = get_user_u32((x), (gaddr));       \
  32        if (!__r && bswap_code(arm_sctlr_b(env))) {     \
  33            (x) = bswap32(x);                           \
  34        }                                               \
  35        __r;                                            \
  36    })
  37
  38#define get_user_code_u16(x, gaddr, env)                \
  39    ({ abi_long __r = get_user_u16((x), (gaddr));       \
  40        if (!__r && bswap_code(arm_sctlr_b(env))) {     \
  41            (x) = bswap16(x);                           \
  42        }                                               \
  43        __r;                                            \
  44    })
  45
  46#define get_user_data_u32(x, gaddr, env)                \
  47    ({ abi_long __r = get_user_u32((x), (gaddr));       \
  48        if (!__r && arm_cpu_bswap_data(env)) {          \
  49            (x) = bswap32(x);                           \
  50        }                                               \
  51        __r;                                            \
  52    })
  53
  54#define get_user_data_u16(x, gaddr, env)                \
  55    ({ abi_long __r = get_user_u16((x), (gaddr));       \
  56        if (!__r && arm_cpu_bswap_data(env)) {          \
  57            (x) = bswap16(x);                           \
  58        }                                               \
  59        __r;                                            \
  60    })
  61
  62#define put_user_data_u32(x, gaddr, env)                \
  63    ({ typeof(x) __x = (x);                             \
  64        if (arm_cpu_bswap_data(env)) {                  \
  65            __x = bswap32(__x);                         \
  66        }                                               \
  67        put_user_u32(__x, (gaddr));                     \
  68    })
  69
  70#define put_user_data_u16(x, gaddr, env)                \
  71    ({ typeof(x) __x = (x);                             \
  72        if (arm_cpu_bswap_data(env)) {                  \
  73            __x = bswap16(__x);                         \
  74        }                                               \
  75        put_user_u16(__x, (gaddr));                     \
  76    })
  77
  78/* Commpage handling -- there is no commpage for AArch64 */
  79
  80/*
  81 * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
  82 * Input:
  83 * r0 = pointer to oldval
  84 * r1 = pointer to newval
  85 * r2 = pointer to target value
  86 *
  87 * Output:
  88 * r0 = 0 if *ptr was changed, non-0 if no exchange happened
  89 * C set if *ptr was changed, clear if no exchange happened
  90 *
  91 * Note segv's in kernel helpers are a bit tricky, we can set the
  92 * data address sensibly but the PC address is just the entry point.
  93 */
  94static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
  95{
  96    uint64_t oldval, newval, val;
  97    uint32_t addr, cpsr;
  98
  99    /* Based on the 32 bit code in do_kernel_trap */
 100
 101    /* XXX: This only works between threads, not between processes.
 102       It's probably possible to implement this with native host
 103       operations. However things like ldrex/strex are much harder so
 104       there's not much point trying.  */
 105    start_exclusive();
 106    cpsr = cpsr_read(env);
 107    addr = env->regs[2];
 108
 109    if (get_user_u64(oldval, env->regs[0])) {
 110        env->exception.vaddress = env->regs[0];
 111        goto segv;
 112    };
 113
 114    if (get_user_u64(newval, env->regs[1])) {
 115        env->exception.vaddress = env->regs[1];
 116        goto segv;
 117    };
 118
 119    if (get_user_u64(val, addr)) {
 120        env->exception.vaddress = addr;
 121        goto segv;
 122    }
 123
 124    if (val == oldval) {
 125        val = newval;
 126
 127        if (put_user_u64(val, addr)) {
 128            env->exception.vaddress = addr;
 129            goto segv;
 130        };
 131
 132        env->regs[0] = 0;
 133        cpsr |= CPSR_C;
 134    } else {
 135        env->regs[0] = -1;
 136        cpsr &= ~CPSR_C;
 137    }
 138    cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
 139    end_exclusive();
 140    return;
 141
 142segv:
 143    end_exclusive();
 144    /* We get the PC of the entry address - which is as good as anything,
 145       on a real kernel what you get depends on which mode it uses. */
 146    /* XXX: check env->error_code */
 147    force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
 148                    env->exception.vaddress);
 149}
 150
 151/* Handle a jump to the kernel code page.  */
 152static int
 153do_kernel_trap(CPUARMState *env)
 154{
 155    uint32_t addr;
 156    uint32_t cpsr;
 157    uint32_t val;
 158
 159    switch (env->regs[15]) {
 160    case 0xffff0fa0: /* __kernel_memory_barrier */
 161        /* ??? No-op. Will need to do better for SMP.  */
 162        break;
 163    case 0xffff0fc0: /* __kernel_cmpxchg */
 164         /* XXX: This only works between threads, not between processes.
 165            It's probably possible to implement this with native host
 166            operations. However things like ldrex/strex are much harder so
 167            there's not much point trying.  */
 168        start_exclusive();
 169        cpsr = cpsr_read(env);
 170        addr = env->regs[2];
 171        /* FIXME: This should SEGV if the access fails.  */
 172        if (get_user_u32(val, addr))
 173            val = ~env->regs[0];
 174        if (val == env->regs[0]) {
 175            val = env->regs[1];
 176            /* FIXME: Check for segfaults.  */
 177            put_user_u32(val, addr);
 178            env->regs[0] = 0;
 179            cpsr |= CPSR_C;
 180        } else {
 181            env->regs[0] = -1;
 182            cpsr &= ~CPSR_C;
 183        }
 184        cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
 185        end_exclusive();
 186        break;
 187    case 0xffff0fe0: /* __kernel_get_tls */
 188        env->regs[0] = cpu_get_tls(env);
 189        break;
 190    case 0xffff0f60: /* __kernel_cmpxchg64 */
 191        arm_kernel_cmpxchg64_helper(env);
 192        break;
 193
 194    default:
 195        return 1;
 196    }
 197    /* Jump back to the caller.  */
 198    addr = env->regs[14];
 199    if (addr & 1) {
 200        env->thumb = 1;
 201        addr &= ~1;
 202    }
 203    env->regs[15] = addr;
 204
 205    return 0;
 206}
 207
 208static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb)
 209{
 210    /*
 211     * Return true if this insn is one of the three magic UDF insns
 212     * which the kernel treats as breakpoint insns.
 213     */
 214    if (!is_thumb) {
 215        return (opcode & 0x0fffffff) == 0x07f001f0;
 216    } else {
 217        /*
 218         * Note that we get the two halves of the 32-bit T32 insn
 219         * in the opposite order to the value the kernel uses in
 220         * its undef_hook struct.
 221         */
 222        return ((opcode & 0xffff) == 0xde01) || (opcode == 0xa000f7f0);
 223    }
 224}
 225
 226static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
 227{
 228    TaskState *ts = env_cpu(env)->opaque;
 229    int rc = EmulateAll(opcode, &ts->fpa, env);
 230    int raise, enabled;
 231
 232    if (rc == 0) {
 233        /* Illegal instruction */
 234        return false;
 235    }
 236    if (rc > 0) {
 237        /* Everything ok. */
 238        env->regs[15] += 4;
 239        return true;
 240    }
 241
 242    /* FP exception */
 243    rc = -rc;
 244    raise = 0;
 245
 246    /* Translate softfloat flags to FPSR flags */
 247    if (rc & float_flag_invalid) {
 248        raise |= BIT_IOC;
 249    }
 250    if (rc & float_flag_divbyzero) {
 251        raise |= BIT_DZC;
 252    }
 253    if (rc & float_flag_overflow) {
 254        raise |= BIT_OFC;
 255    }
 256    if (rc & float_flag_underflow) {
 257        raise |= BIT_UFC;
 258    }
 259    if (rc & float_flag_inexact) {
 260        raise |= BIT_IXC;
 261    }
 262
 263    /* Accumulate unenabled exceptions */
 264    enabled = ts->fpa.fpsr >> 16;
 265    ts->fpa.fpsr |= raise & ~enabled;
 266
 267    if (raise & enabled) {
 268        /*
 269         * The kernel's nwfpe emulator does not pass a real si_code.
 270         * It merely uses send_sig(SIGFPE, current, 1), which results in
 271         * __send_signal() filling out SI_KERNEL with pid and uid 0 (under
 272         * the "SEND_SIG_PRIV" case). That's what our force_sig() does.
 273         */
 274        force_sig(TARGET_SIGFPE);
 275    } else {
 276        env->regs[15] += 4;
 277    }
 278    return true;
 279}
 280
 281void cpu_loop(CPUARMState *env)
 282{
 283    CPUState *cs = env_cpu(env);
 284    int trapnr, si_signo, si_code;
 285    unsigned int n, insn;
 286    abi_ulong ret;
 287
 288    for(;;) {
 289        cpu_exec_start(cs);
 290        trapnr = cpu_exec(cs);
 291        cpu_exec_end(cs);
 292        process_queued_cpu_work(cs);
 293
 294        switch(trapnr) {
 295        case EXCP_UDEF:
 296        case EXCP_NOCP:
 297        case EXCP_INVSTATE:
 298            {
 299                uint32_t opcode;
 300
 301                /* we handle the FPU emulation here, as Linux */
 302                /* we get the opcode */
 303                /* FIXME - what to do if get_user() fails? */
 304                get_user_code_u32(opcode, env->regs[15], env);
 305
 306                /*
 307                 * The Linux kernel treats some UDF patterns specially
 308                 * to use as breakpoints (instead of the architectural
 309                 * bkpt insn). These should trigger a SIGTRAP rather
 310                 * than SIGILL.
 311                 */
 312                if (insn_is_linux_bkpt(opcode, env->thumb)) {
 313                    goto excp_debug;
 314                }
 315
 316                if (!env->thumb && emulate_arm_fpa11(env, opcode)) {
 317                    break;
 318                }
 319
 320                force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN,
 321                                env->regs[15]);
 322            }
 323            break;
 324        case EXCP_SWI:
 325            {
 326                env->eabi = 1;
 327                /* system call */
 328                if (env->thumb) {
 329                    /* Thumb is always EABI style with syscall number in r7 */
 330                    n = env->regs[7];
 331                } else {
 332                    /*
 333                     * Equivalent of kernel CONFIG_OABI_COMPAT: read the
 334                     * Arm SVC insn to extract the immediate, which is the
 335                     * syscall number in OABI.
 336                     */
 337                    /* FIXME - what to do if get_user() fails? */
 338                    get_user_code_u32(insn, env->regs[15] - 4, env);
 339                    n = insn & 0xffffff;
 340                    if (n == 0) {
 341                        /* zero immediate: EABI, syscall number in r7 */
 342                        n = env->regs[7];
 343                    } else {
 344                        /*
 345                         * This XOR matches the kernel code: an immediate
 346                         * in the valid range (0x900000 .. 0x9fffff) is
 347                         * converted into the correct EABI-style syscall
 348                         * number; invalid immediates end up as values
 349                         * > 0xfffff and are handled below as out-of-range.
 350                         */
 351                        n ^= ARM_SYSCALL_BASE;
 352                        env->eabi = 0;
 353                    }
 354                }
 355
 356                if (n > ARM_NR_BASE) {
 357                    switch (n) {
 358                    case ARM_NR_cacheflush:
 359                        /* nop */
 360                        break;
 361                    case ARM_NR_set_tls:
 362                        cpu_set_tls(env, env->regs[0]);
 363                        env->regs[0] = 0;
 364                        break;
 365                    case ARM_NR_breakpoint:
 366                        env->regs[15] -= env->thumb ? 2 : 4;
 367                        goto excp_debug;
 368                    case ARM_NR_get_tls:
 369                        env->regs[0] = cpu_get_tls(env);
 370                        break;
 371                    default:
 372                        if (n < 0xf0800) {
 373                            /*
 374                             * Syscalls 0xf0000..0xf07ff (or 0x9f0000..
 375                             * 0x9f07ff in OABI numbering) are defined
 376                             * to return -ENOSYS rather than raising
 377                             * SIGILL. Note that we have already
 378                             * removed the 0x900000 prefix.
 379                             */
 380                            qemu_log_mask(LOG_UNIMP,
 381                                "qemu: Unsupported ARM syscall: 0x%x\n",
 382                                          n);
 383                            env->regs[0] = -TARGET_ENOSYS;
 384                        } else {
 385                            /*
 386                             * Otherwise SIGILL. This includes any SWI with
 387                             * immediate not originally 0x9fxxxx, because
 388                             * of the earlier XOR.
 389                             * Like the real kernel, we report the addr of the
 390                             * SWI in the siginfo si_addr but leave the PC
 391                             * pointing at the insn after the SWI.
 392                             */
 393                            abi_ulong faultaddr = env->regs[15];
 394                            faultaddr -= env->thumb ? 2 : 4;
 395                            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP,
 396                                            faultaddr);
 397                        }
 398                        break;
 399                    }
 400                } else {
 401                    ret = do_syscall(env,
 402                                     n,
 403                                     env->regs[0],
 404                                     env->regs[1],
 405                                     env->regs[2],
 406                                     env->regs[3],
 407                                     env->regs[4],
 408                                     env->regs[5],
 409                                     0, 0);
 410                    if (ret == -TARGET_ERESTARTSYS) {
 411                        env->regs[15] -= env->thumb ? 2 : 4;
 412                    } else if (ret != -TARGET_QEMU_ESIGRETURN) {
 413                        env->regs[0] = ret;
 414                    }
 415                }
 416            }
 417            break;
 418        case EXCP_SEMIHOST:
 419            env->regs[0] = do_common_semihosting(cs);
 420            env->regs[15] += env->thumb ? 2 : 4;
 421            break;
 422        case EXCP_INTERRUPT:
 423            /* just indicate that signals should be handled asap */
 424            break;
 425        case EXCP_PREFETCH_ABORT:
 426        case EXCP_DATA_ABORT:
 427            /* For user-only we don't set TTBCR_EAE, so look at the FSR. */
 428            switch (env->exception.fsr & 0x1f) {
 429            case 0x1: /* Alignment */
 430                si_signo = TARGET_SIGBUS;
 431                si_code = TARGET_BUS_ADRALN;
 432                break;
 433            case 0x3: /* Access flag fault, level 1 */
 434            case 0x6: /* Access flag fault, level 2 */
 435            case 0x9: /* Domain fault, level 1 */
 436            case 0xb: /* Domain fault, level 2 */
 437            case 0xd: /* Permision fault, level 1 */
 438            case 0xf: /* Permision fault, level 2 */
 439                si_signo = TARGET_SIGSEGV;
 440                si_code = TARGET_SEGV_ACCERR;
 441                break;
 442            case 0x5: /* Translation fault, level 1 */
 443            case 0x7: /* Translation fault, level 2 */
 444                si_signo = TARGET_SIGSEGV;
 445                si_code = TARGET_SEGV_MAPERR;
 446                break;
 447            default:
 448                g_assert_not_reached();
 449            }
 450            force_sig_fault(si_signo, si_code, env->exception.vaddress);
 451            break;
 452        case EXCP_DEBUG:
 453        case EXCP_BKPT:
 454        excp_debug:
 455            force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]);
 456            break;
 457        case EXCP_KERNEL_TRAP:
 458            if (do_kernel_trap(env))
 459              goto error;
 460            break;
 461        case EXCP_YIELD:
 462            /* nothing to do here for user-mode, just resume guest code */
 463            break;
 464        case EXCP_ATOMIC:
 465            cpu_exec_step_atomic(cs);
 466            break;
 467        default:
 468        error:
 469            EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
 470            abort();
 471        }
 472        process_pending_signals(env);
 473    }
 474}
 475
 476void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 477{
 478    CPUState *cpu = env_cpu(env);
 479    TaskState *ts = cpu->opaque;
 480    struct image_info *info = ts->info;
 481    int i;
 482
 483    cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
 484               CPSRWriteByInstr);
 485    for(i = 0; i < 16; i++) {
 486        env->regs[i] = regs->uregs[i];
 487    }
 488#ifdef TARGET_WORDS_BIGENDIAN
 489    /* Enable BE8.  */
 490    if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
 491        && (info->elf_flags & EF_ARM_BE8)) {
 492        env->uncached_cpsr |= CPSR_E;
 493        env->cp15.sctlr_el[1] |= SCTLR_E0E;
 494    } else {
 495        env->cp15.sctlr_el[1] |= SCTLR_B;
 496    }
 497    arm_rebuild_hflags(env);
 498#endif
 499
 500    ts->stack_base = info->start_stack;
 501    ts->heap_base = info->brk;
 502    /* This will be filled in on the first SYS_HEAPINFO call.  */
 503    ts->heap_limit = 0;
 504}
 505