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