qemu/linux-user/s390x/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 "cpu_loop-common.h"
  24
  25/* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */
  26#define S390X_FAIL_ADDR_MASK -4096LL
  27
  28void cpu_loop(CPUS390XState *env)
  29{
  30    CPUState *cs = env_cpu(env);
  31    int trapnr, n, sig;
  32    target_siginfo_t info;
  33    target_ulong addr;
  34    abi_long ret;
  35
  36    while (1) {
  37        cpu_exec_start(cs);
  38        trapnr = cpu_exec(cs);
  39        cpu_exec_end(cs);
  40        process_queued_cpu_work(cs);
  41
  42        switch (trapnr) {
  43        case EXCP_INTERRUPT:
  44            /* Just indicate that signals should be handled asap.  */
  45            break;
  46
  47        case EXCP_SVC:
  48            n = env->int_svc_code;
  49            if (!n) {
  50                /* syscalls > 255 */
  51                n = env->regs[1];
  52            }
  53            env->psw.addr += env->int_svc_ilen;
  54            ret = do_syscall(env, n, env->regs[2], env->regs[3],
  55                             env->regs[4], env->regs[5],
  56                             env->regs[6], env->regs[7], 0, 0);
  57            if (ret == -TARGET_ERESTARTSYS) {
  58                env->psw.addr -= env->int_svc_ilen;
  59            } else if (ret != -TARGET_QEMU_ESIGRETURN) {
  60                env->regs[2] = ret;
  61            }
  62            break;
  63
  64        case EXCP_DEBUG:
  65            sig = TARGET_SIGTRAP;
  66            n = TARGET_TRAP_BRKPT;
  67            goto do_signal_pc;
  68        case EXCP_PGM:
  69            n = env->int_pgm_code;
  70            switch (n) {
  71            case PGM_OPERATION:
  72            case PGM_PRIVILEGED:
  73                sig = TARGET_SIGILL;
  74                n = TARGET_ILL_ILLOPC;
  75                goto do_signal_pc;
  76            case PGM_PROTECTION:
  77            case PGM_ADDRESSING:
  78                sig = TARGET_SIGSEGV;
  79                /* XXX: check env->error_code */
  80                n = TARGET_SEGV_MAPERR;
  81                addr = env->__excp_addr & S390X_FAIL_ADDR_MASK;
  82                goto do_signal;
  83            case PGM_EXECUTE:
  84            case PGM_SPECIFICATION:
  85            case PGM_SPECIAL_OP:
  86            case PGM_OPERAND:
  87            do_sigill_opn:
  88                sig = TARGET_SIGILL;
  89                n = TARGET_ILL_ILLOPN;
  90                goto do_signal_pc;
  91
  92            case PGM_FIXPT_OVERFLOW:
  93                sig = TARGET_SIGFPE;
  94                n = TARGET_FPE_INTOVF;
  95                goto do_signal_pc;
  96            case PGM_FIXPT_DIVIDE:
  97                sig = TARGET_SIGFPE;
  98                n = TARGET_FPE_INTDIV;
  99                goto do_signal_pc;
 100
 101            case PGM_DATA:
 102                n = (env->fpc >> 8) & 0xff;
 103                if (n == 0xff) {
 104                    /* compare-and-trap */
 105                    goto do_sigill_opn;
 106                } else {
 107                    /* An IEEE exception, simulated or otherwise.  */
 108                    if (n & 0x80) {
 109                        n = TARGET_FPE_FLTINV;
 110                    } else if (n & 0x40) {
 111                        n = TARGET_FPE_FLTDIV;
 112                    } else if (n & 0x20) {
 113                        n = TARGET_FPE_FLTOVF;
 114                    } else if (n & 0x10) {
 115                        n = TARGET_FPE_FLTUND;
 116                    } else if (n & 0x08) {
 117                        n = TARGET_FPE_FLTRES;
 118                    } else {
 119                        /* ??? Quantum exception; BFP, DFP error.  */
 120                        goto do_sigill_opn;
 121                    }
 122                    sig = TARGET_SIGFPE;
 123                    goto do_signal_pc;
 124                }
 125
 126            default:
 127                fprintf(stderr, "Unhandled program exception: %#x\n", n);
 128                cpu_dump_state(cs, stderr, 0);
 129                exit(EXIT_FAILURE);
 130            }
 131            break;
 132
 133        do_signal_pc:
 134            addr = env->psw.addr;
 135        do_signal:
 136            info.si_signo = sig;
 137            info.si_errno = 0;
 138            info.si_code = n;
 139            info._sifields._sigfault._addr = addr;
 140            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 141            break;
 142
 143        case EXCP_ATOMIC:
 144            cpu_exec_step_atomic(cs);
 145            break;
 146        default:
 147            fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
 148            cpu_dump_state(cs, stderr, 0);
 149            exit(EXIT_FAILURE);
 150        }
 151        process_pending_signals (env);
 152    }
 153}
 154
 155void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 156{
 157    int i;
 158    for (i = 0; i < 16; i++) {
 159        env->regs[i] = regs->gprs[i];
 160    }
 161    env->psw.mask = regs->psw.mask;
 162    env->psw.addr = regs->psw.addr;
 163}
 164