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 24 void 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 = gdb_handlesig(cs, TARGET_SIGTRAP); 183 if (info.si_signo) { 184 info.si_errno = 0; 185 info.si_code = TARGET_TRAP_BRKPT; 186 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 187 } else { 188 arch_interrupt = false; 189 } 190 break; 191 case EXCP_INTERRUPT: 192 /* Just indicate that signals should be handled asap. */ 193 break; 194 case EXCP_ATOMIC: 195 cpu_exec_step_atomic(cs); 196 arch_interrupt = false; 197 break; 198 default: 199 fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); 200 cpu_dump_state(cs, stderr, fprintf, 0); 201 exit(EXIT_FAILURE); 202 } 203 process_pending_signals (env); 204 205 /* Most of the traps imply a transition through PALcode, which 206 implies an REI instruction has been executed. Which means 207 that RX and LOCK_ADDR should be cleared. But there are a 208 few exceptions for traps internal to QEMU. */ 209 if (arch_interrupt) { 210 env->flags &= ~ENV_FLAG_RX_FLAG; 211 env->lock_addr = -1; 212 } 213 } 214 } 215 216 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 217 { 218 int i; 219 220 for(i = 0; i < 28; i++) { 221 env->ir[i] = ((abi_ulong *)regs)[i]; 222 } 223 env->ir[IR_SP] = regs->usp; 224 env->pc = regs->pc; 225 } 226