qemu/linux-user/alpha/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.h"
  22#include "cpu_loop-common.h"
  23
  24void cpu_loop(CPUAlphaState *env)
  25{
  26    CPUState *cs = CPU(alpha_env_get_cpu(env));
  27    int trapnr;
  28    target_siginfo_t info;
  29    abi_long sysret;
  30
  31    while (1) {
  32        bool arch_interrupt = true;
  33
  34        cpu_exec_start(cs);
  35        trapnr = cpu_exec(cs);
  36        cpu_exec_end(cs);
  37        process_queued_cpu_work(cs);
  38
  39        switch (trapnr) {
  40        case EXCP_RESET:
  41            fprintf(stderr, "Reset requested. Exit\n");
  42            exit(EXIT_FAILURE);
  43            break;
  44        case EXCP_MCHK:
  45            fprintf(stderr, "Machine check exception. Exit\n");
  46            exit(EXIT_FAILURE);
  47            break;
  48        case EXCP_SMP_INTERRUPT:
  49        case EXCP_CLK_INTERRUPT:
  50        case EXCP_DEV_INTERRUPT:
  51            fprintf(stderr, "External interrupt. Exit\n");
  52            exit(EXIT_FAILURE);
  53            break;
  54        case EXCP_MMFAULT:
  55            info.si_signo = TARGET_SIGSEGV;
  56            info.si_errno = 0;
  57            info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
  58                            ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
  59            info._sifields._sigfault._addr = env->trap_arg0;
  60            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
  61            break;
  62        case EXCP_UNALIGN:
  63            info.si_signo = TARGET_SIGBUS;
  64            info.si_errno = 0;
  65            info.si_code = TARGET_BUS_ADRALN;
  66            info._sifields._sigfault._addr = env->trap_arg0;
  67            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
  68            break;
  69        case EXCP_OPCDEC:
  70        do_sigill:
  71            info.si_signo = TARGET_SIGILL;
  72            info.si_errno = 0;
  73            info.si_code = TARGET_ILL_ILLOPC;
  74            info._sifields._sigfault._addr = env->pc;
  75            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
  76            break;
  77        case EXCP_ARITH:
  78            info.si_signo = TARGET_SIGFPE;
  79            info.si_errno = 0;
  80            info.si_code = TARGET_FPE_FLTINV;
  81            info._sifields._sigfault._addr = env->pc;
  82            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
  83            break;
  84        case EXCP_FEN:
  85            /* No-op.  Linux simply re-enables the FPU.  */
  86            break;
  87        case EXCP_CALL_PAL:
  88            switch (env->error_code) {
  89            case 0x80:
  90                /* BPT */
  91                info.si_signo = TARGET_SIGTRAP;
  92                info.si_errno = 0;
  93                info.si_code = TARGET_TRAP_BRKPT;
  94                info._sifields._sigfault._addr = env->pc;
  95                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
  96                break;
  97            case 0x81:
  98                /* BUGCHK */
  99                info.si_signo = TARGET_SIGTRAP;
 100                info.si_errno = 0;
 101                info.si_code = 0;
 102                info._sifields._sigfault._addr = env->pc;
 103                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 104                break;
 105            case 0x83:
 106                /* CALLSYS */
 107                trapnr = env->ir[IR_V0];
 108                sysret = do_syscall(env, trapnr,
 109                                    env->ir[IR_A0], env->ir[IR_A1],
 110                                    env->ir[IR_A2], env->ir[IR_A3],
 111                                    env->ir[IR_A4], env->ir[IR_A5],
 112                                    0, 0);
 113                if (sysret == -TARGET_ERESTARTSYS) {
 114                    env->pc -= 4;
 115                    break;
 116                }
 117                if (sysret == -TARGET_QEMU_ESIGRETURN) {
 118                    break;
 119                }
 120                /* Syscall writes 0 to V0 to bypass error check, similar
 121                   to how this is handled internal to Linux kernel.
 122                   (Ab)use trapnr temporarily as boolean indicating error.  */
 123                trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
 124                env->ir[IR_V0] = (trapnr ? -sysret : sysret);
 125                env->ir[IR_A3] = trapnr;
 126                break;
 127            case 0x86:
 128                /* IMB */
 129                /* ??? We can probably elide the code using page_unprotect
 130                   that is checking for self-modifying code.  Instead we
 131                   could simply call tb_flush here.  Until we work out the
 132                   changes required to turn off the extra write protection,
 133                   this can be a no-op.  */
 134                break;
 135            case 0x9E:
 136                /* RDUNIQUE */
 137                /* Handled in the translator for usermode.  */
 138                abort();
 139            case 0x9F:
 140                /* WRUNIQUE */
 141                /* Handled in the translator for usermode.  */
 142                abort();
 143            case 0xAA:
 144                /* GENTRAP */
 145                info.si_signo = TARGET_SIGFPE;
 146                switch (env->ir[IR_A0]) {
 147                case TARGET_GEN_INTOVF:
 148                    info.si_code = TARGET_FPE_INTOVF;
 149                    break;
 150                case TARGET_GEN_INTDIV:
 151                    info.si_code = TARGET_FPE_INTDIV;
 152                    break;
 153                case TARGET_GEN_FLTOVF:
 154                    info.si_code = TARGET_FPE_FLTOVF;
 155                    break;
 156                case TARGET_GEN_FLTUND:
 157                    info.si_code = TARGET_FPE_FLTUND;
 158                    break;
 159                case TARGET_GEN_FLTINV:
 160                    info.si_code = TARGET_FPE_FLTINV;
 161                    break;
 162                case TARGET_GEN_FLTINE:
 163                    info.si_code = TARGET_FPE_FLTRES;
 164                    break;
 165                case TARGET_GEN_ROPRAND:
 166                    info.si_code = 0;
 167                    break;
 168                default:
 169                    info.si_signo = TARGET_SIGTRAP;
 170                    info.si_code = 0;
 171                    break;
 172                }
 173                info.si_errno = 0;
 174                info._sifields._sigfault._addr = env->pc;
 175                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 176                break;
 177            default:
 178                goto do_sigill;
 179            }
 180            break;
 181        case EXCP_DEBUG:
 182            info.si_signo = TARGET_SIGTRAP;
 183            info.si_errno = 0;
 184            info.si_code = TARGET_TRAP_BRKPT;
 185            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 186            break;
 187        case EXCP_INTERRUPT:
 188            /* Just indicate that signals should be handled asap.  */
 189            break;
 190        case EXCP_ATOMIC:
 191            cpu_exec_step_atomic(cs);
 192            arch_interrupt = false;
 193            break;
 194        default:
 195            fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
 196            cpu_dump_state(cs, stderr, fprintf, 0);
 197            exit(EXIT_FAILURE);
 198        }
 199        process_pending_signals (env);
 200
 201        /* Most of the traps imply a transition through PALcode, which
 202           implies an REI instruction has been executed.  Which means
 203           that RX and LOCK_ADDR should be cleared.  But there are a
 204           few exceptions for traps internal to QEMU.  */
 205        if (arch_interrupt) {
 206            env->flags &= ~ENV_FLAG_RX_FLAG;
 207            env->lock_addr = -1;
 208        }
 209    }
 210}
 211
 212void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 213{
 214    int i;
 215
 216    for(i = 0; i < 28; i++) {
 217        env->ir[i] = ((abi_ulong *)regs)[i];
 218    }
 219    env->ir[IR_SP] = regs->usp;
 220    env->pc = regs->pc;
 221}
 222