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 "elf.h" 24 #include "cpu_loop-common.h" 25 26 #define get_user_code_u32(x, gaddr, env) \ 27 ({ abi_long __r = get_user_u32((x), (gaddr)); \ 28 if (!__r && bswap_code(arm_sctlr_b(env))) { \ 29 (x) = bswap32(x); \ 30 } \ 31 __r; \ 32 }) 33 34 #define get_user_code_u16(x, gaddr, env) \ 35 ({ abi_long __r = get_user_u16((x), (gaddr)); \ 36 if (!__r && bswap_code(arm_sctlr_b(env))) { \ 37 (x) = bswap16(x); \ 38 } \ 39 __r; \ 40 }) 41 42 #define get_user_data_u32(x, gaddr, env) \ 43 ({ abi_long __r = get_user_u32((x), (gaddr)); \ 44 if (!__r && arm_cpu_bswap_data(env)) { \ 45 (x) = bswap32(x); \ 46 } \ 47 __r; \ 48 }) 49 50 #define get_user_data_u16(x, gaddr, env) \ 51 ({ abi_long __r = get_user_u16((x), (gaddr)); \ 52 if (!__r && arm_cpu_bswap_data(env)) { \ 53 (x) = bswap16(x); \ 54 } \ 55 __r; \ 56 }) 57 58 #define put_user_data_u32(x, gaddr, env) \ 59 ({ typeof(x) __x = (x); \ 60 if (arm_cpu_bswap_data(env)) { \ 61 __x = bswap32(__x); \ 62 } \ 63 put_user_u32(__x, (gaddr)); \ 64 }) 65 66 #define put_user_data_u16(x, gaddr, env) \ 67 ({ typeof(x) __x = (x); \ 68 if (arm_cpu_bswap_data(env)) { \ 69 __x = bswap16(__x); \ 70 } \ 71 put_user_u16(__x, (gaddr)); \ 72 }) 73 74 /* Commpage handling -- there is no commpage for AArch64 */ 75 76 /* 77 * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt 78 * Input: 79 * r0 = pointer to oldval 80 * r1 = pointer to newval 81 * r2 = pointer to target value 82 * 83 * Output: 84 * r0 = 0 if *ptr was changed, non-0 if no exchange happened 85 * C set if *ptr was changed, clear if no exchange happened 86 * 87 * Note segv's in kernel helpers are a bit tricky, we can set the 88 * data address sensibly but the PC address is just the entry point. 89 */ 90 static void arm_kernel_cmpxchg64_helper(CPUARMState *env) 91 { 92 uint64_t oldval, newval, val; 93 uint32_t addr, cpsr; 94 target_siginfo_t info; 95 96 /* Based on the 32 bit code in do_kernel_trap */ 97 98 /* XXX: This only works between threads, not between processes. 99 It's probably possible to implement this with native host 100 operations. However things like ldrex/strex are much harder so 101 there's not much point trying. */ 102 start_exclusive(); 103 cpsr = cpsr_read(env); 104 addr = env->regs[2]; 105 106 if (get_user_u64(oldval, env->regs[0])) { 107 env->exception.vaddress = env->regs[0]; 108 goto segv; 109 }; 110 111 if (get_user_u64(newval, env->regs[1])) { 112 env->exception.vaddress = env->regs[1]; 113 goto segv; 114 }; 115 116 if (get_user_u64(val, addr)) { 117 env->exception.vaddress = addr; 118 goto segv; 119 } 120 121 if (val == oldval) { 122 val = newval; 123 124 if (put_user_u64(val, addr)) { 125 env->exception.vaddress = addr; 126 goto segv; 127 }; 128 129 env->regs[0] = 0; 130 cpsr |= CPSR_C; 131 } else { 132 env->regs[0] = -1; 133 cpsr &= ~CPSR_C; 134 } 135 cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr); 136 end_exclusive(); 137 return; 138 139 segv: 140 end_exclusive(); 141 /* We get the PC of the entry address - which is as good as anything, 142 on a real kernel what you get depends on which mode it uses. */ 143 info.si_signo = TARGET_SIGSEGV; 144 info.si_errno = 0; 145 /* XXX: check env->error_code */ 146 info.si_code = TARGET_SEGV_MAPERR; 147 info._sifields._sigfault._addr = env->exception.vaddress; 148 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 149 } 150 151 /* Handle a jump to the kernel code page. */ 152 static int 153 do_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 208 void cpu_loop(CPUARMState *env) 209 { 210 CPUState *cs = env_cpu(env); 211 int trapnr; 212 unsigned int n, insn; 213 target_siginfo_t info; 214 uint32_t addr; 215 abi_ulong ret; 216 217 for(;;) { 218 cpu_exec_start(cs); 219 trapnr = cpu_exec(cs); 220 cpu_exec_end(cs); 221 process_queued_cpu_work(cs); 222 223 switch(trapnr) { 224 case EXCP_UDEF: 225 case EXCP_NOCP: 226 case EXCP_INVSTATE: 227 { 228 TaskState *ts = cs->opaque; 229 uint32_t opcode; 230 int rc; 231 232 /* we handle the FPU emulation here, as Linux */ 233 /* we get the opcode */ 234 /* FIXME - what to do if get_user() fails? */ 235 get_user_code_u32(opcode, env->regs[15], env); 236 237 rc = EmulateAll(opcode, &ts->fpa, env); 238 if (rc == 0) { /* illegal instruction */ 239 info.si_signo = TARGET_SIGILL; 240 info.si_errno = 0; 241 info.si_code = TARGET_ILL_ILLOPN; 242 info._sifields._sigfault._addr = env->regs[15]; 243 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 244 } else if (rc < 0) { /* FP exception */ 245 int arm_fpe=0; 246 247 /* translate softfloat flags to FPSR flags */ 248 if (-rc & float_flag_invalid) 249 arm_fpe |= BIT_IOC; 250 if (-rc & float_flag_divbyzero) 251 arm_fpe |= BIT_DZC; 252 if (-rc & float_flag_overflow) 253 arm_fpe |= BIT_OFC; 254 if (-rc & float_flag_underflow) 255 arm_fpe |= BIT_UFC; 256 if (-rc & float_flag_inexact) 257 arm_fpe |= BIT_IXC; 258 259 FPSR fpsr = ts->fpa.fpsr; 260 //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); 261 262 if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ 263 info.si_signo = TARGET_SIGFPE; 264 info.si_errno = 0; 265 266 /* ordered by priority, least first */ 267 if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; 268 if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; 269 if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; 270 if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; 271 if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; 272 273 info._sifields._sigfault._addr = env->regs[15]; 274 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 275 } else { 276 env->regs[15] += 4; 277 } 278 279 /* accumulate unenabled exceptions */ 280 if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) 281 fpsr |= BIT_IXC; 282 if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) 283 fpsr |= BIT_UFC; 284 if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) 285 fpsr |= BIT_OFC; 286 if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) 287 fpsr |= BIT_DZC; 288 if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) 289 fpsr |= BIT_IOC; 290 ts->fpa.fpsr=fpsr; 291 } else { /* everything OK */ 292 /* increment PC */ 293 env->regs[15] += 4; 294 } 295 } 296 break; 297 case EXCP_SWI: 298 { 299 env->eabi = 1; 300 /* system call */ 301 if (env->thumb) { 302 /* Thumb is always EABI style with syscall number in r7 */ 303 n = env->regs[7]; 304 } else { 305 /* 306 * Equivalent of kernel CONFIG_OABI_COMPAT: read the 307 * Arm SVC insn to extract the immediate, which is the 308 * syscall number in OABI. 309 */ 310 /* FIXME - what to do if get_user() fails? */ 311 get_user_code_u32(insn, env->regs[15] - 4, env); 312 n = insn & 0xffffff; 313 if (n == 0) { 314 /* zero immediate: EABI, syscall number in r7 */ 315 n = env->regs[7]; 316 } else { 317 /* 318 * This XOR matches the kernel code: an immediate 319 * in the valid range (0x900000 .. 0x9fffff) is 320 * converted into the correct EABI-style syscall 321 * number; invalid immediates end up as values 322 * > 0xfffff and are handled below as out-of-range. 323 */ 324 n ^= ARM_SYSCALL_BASE; 325 env->eabi = 0; 326 } 327 } 328 329 if (n > ARM_NR_BASE) { 330 switch (n) { 331 case ARM_NR_cacheflush: 332 /* nop */ 333 break; 334 case ARM_NR_set_tls: 335 cpu_set_tls(env, env->regs[0]); 336 env->regs[0] = 0; 337 break; 338 case ARM_NR_breakpoint: 339 env->regs[15] -= env->thumb ? 2 : 4; 340 goto excp_debug; 341 case ARM_NR_get_tls: 342 env->regs[0] = cpu_get_tls(env); 343 break; 344 default: 345 if (n < 0xf0800) { 346 /* 347 * Syscalls 0xf0000..0xf07ff (or 0x9f0000.. 348 * 0x9f07ff in OABI numbering) are defined 349 * to return -ENOSYS rather than raising 350 * SIGILL. Note that we have already 351 * removed the 0x900000 prefix. 352 */ 353 qemu_log_mask(LOG_UNIMP, 354 "qemu: Unsupported ARM syscall: 0x%x\n", 355 n); 356 env->regs[0] = -TARGET_ENOSYS; 357 } else { 358 /* 359 * Otherwise SIGILL. This includes any SWI with 360 * immediate not originally 0x9fxxxx, because 361 * of the earlier XOR. 362 */ 363 info.si_signo = TARGET_SIGILL; 364 info.si_errno = 0; 365 info.si_code = TARGET_ILL_ILLTRP; 366 info._sifields._sigfault._addr = env->regs[15]; 367 if (env->thumb) { 368 info._sifields._sigfault._addr -= 2; 369 } else { 370 info._sifields._sigfault._addr -= 4; 371 } 372 queue_signal(env, info.si_signo, 373 QEMU_SI_FAULT, &info); 374 } 375 break; 376 } 377 } else { 378 ret = do_syscall(env, 379 n, 380 env->regs[0], 381 env->regs[1], 382 env->regs[2], 383 env->regs[3], 384 env->regs[4], 385 env->regs[5], 386 0, 0); 387 if (ret == -TARGET_ERESTARTSYS) { 388 env->regs[15] -= env->thumb ? 2 : 4; 389 } else if (ret != -TARGET_QEMU_ESIGRETURN) { 390 env->regs[0] = ret; 391 } 392 } 393 } 394 break; 395 case EXCP_SEMIHOST: 396 env->regs[0] = do_arm_semihosting(env); 397 env->regs[15] += env->thumb ? 2 : 4; 398 break; 399 case EXCP_INTERRUPT: 400 /* just indicate that signals should be handled asap */ 401 break; 402 case EXCP_PREFETCH_ABORT: 403 case EXCP_DATA_ABORT: 404 addr = env->exception.vaddress; 405 { 406 info.si_signo = TARGET_SIGSEGV; 407 info.si_errno = 0; 408 /* XXX: check env->error_code */ 409 info.si_code = TARGET_SEGV_MAPERR; 410 info._sifields._sigfault._addr = addr; 411 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 412 } 413 break; 414 case EXCP_DEBUG: 415 case EXCP_BKPT: 416 excp_debug: 417 info.si_signo = TARGET_SIGTRAP; 418 info.si_errno = 0; 419 info.si_code = TARGET_TRAP_BRKPT; 420 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 421 break; 422 case EXCP_KERNEL_TRAP: 423 if (do_kernel_trap(env)) 424 goto error; 425 break; 426 case EXCP_YIELD: 427 /* nothing to do here for user-mode, just resume guest code */ 428 break; 429 case EXCP_ATOMIC: 430 cpu_exec_step_atomic(cs); 431 break; 432 default: 433 error: 434 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); 435 abort(); 436 } 437 process_pending_signals(env); 438 } 439 } 440 441 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 442 { 443 CPUState *cpu = env_cpu(env); 444 TaskState *ts = cpu->opaque; 445 struct image_info *info = ts->info; 446 int i; 447 448 cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC, 449 CPSRWriteByInstr); 450 for(i = 0; i < 16; i++) { 451 env->regs[i] = regs->uregs[i]; 452 } 453 #ifdef TARGET_WORDS_BIGENDIAN 454 /* Enable BE8. */ 455 if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4 456 && (info->elf_flags & EF_ARM_BE8)) { 457 env->uncached_cpsr |= CPSR_E; 458 env->cp15.sctlr_el[1] |= SCTLR_E0E; 459 } else { 460 env->cp15.sctlr_el[1] |= SCTLR_B; 461 } 462 arm_rebuild_hflags(env); 463 #endif 464 465 ts->stack_base = info->start_stack; 466 ts->heap_base = info->brk; 467 /* This will be filled in on the first SYS_HEAPINFO call. */ 468 ts->heap_limit = 0; 469 } 470