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