1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * QEMU LoongArch user cpu_loop. 4 * 5 * Copyright (c) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu.h" 10 #include "user-internals.h" 11 #include "user/cpu_loop.h" 12 #include "signal-common.h" 13 14 /* Break codes */ 15 enum { 16 BRK_OVERFLOW = 6, 17 BRK_DIVZERO = 7 18 }; 19 20 void cpu_loop(CPULoongArchState *env) 21 { 22 CPUState *cs = env_cpu(env); 23 int trapnr, si_code; 24 abi_long ret; 25 26 for (;;) { 27 cpu_exec_start(cs); 28 trapnr = cpu_exec(cs); 29 cpu_exec_end(cs); 30 process_queued_cpu_work(cs); 31 32 switch (trapnr) { 33 case EXCP_INTERRUPT: 34 /* just indicate that signals should be handled asap */ 35 break; 36 case EXCCODE_SYS: 37 env->pc += 4; 38 ret = do_syscall(env, env->gpr[11], 39 env->gpr[4], env->gpr[5], 40 env->gpr[6], env->gpr[7], 41 env->gpr[8], env->gpr[9], 42 -1, -1); 43 if (ret == -QEMU_ERESTARTSYS) { 44 env->pc -= 4; 45 break; 46 } 47 if (ret == -QEMU_ESIGRETURN) { 48 /* 49 * Returning from a successful sigreturn syscall. 50 * Avoid clobbering register state. 51 */ 52 break; 53 } 54 env->gpr[4] = ret; 55 break; 56 case EXCCODE_INE: 57 force_sig_fault(TARGET_SIGILL, 0, env->pc); 58 break; 59 case EXCCODE_FPE: 60 si_code = TARGET_FPE_FLTUNK; 61 if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { 62 si_code = TARGET_FPE_FLTINV; 63 } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) { 64 si_code = TARGET_FPE_FLTDIV; 65 } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) { 66 si_code = TARGET_FPE_FLTOVF; 67 } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) { 68 si_code = TARGET_FPE_FLTUND; 69 } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) { 70 si_code = TARGET_FPE_FLTRES; 71 } 72 force_sig_fault(TARGET_SIGFPE, si_code, env->pc); 73 break; 74 case EXCP_DEBUG: 75 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); 76 break; 77 case EXCCODE_BRK: 78 { 79 unsigned int opcode; 80 81 get_user_u32(opcode, env->pc); 82 83 switch (opcode & 0x7fff) { 84 case BRK_OVERFLOW: 85 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc); 86 break; 87 case BRK_DIVZERO: 88 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); 89 break; 90 default: 91 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); 92 } 93 } 94 break; 95 case EXCCODE_BCE: 96 force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc); 97 break; 98 99 /* 100 * Begin with LSX and LASX disabled, then enable on the first trap. 101 * In this way we can tell if the unit is in use. This is used to 102 * choose the layout of any signal frame. 103 */ 104 case EXCCODE_SXD: 105 env->CSR_EUEN |= R_CSR_EUEN_SXE_MASK; 106 break; 107 case EXCCODE_ASXD: 108 env->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK; 109 break; 110 111 case EXCP_ATOMIC: 112 cpu_exec_step_atomic(cs); 113 break; 114 default: 115 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", 116 trapnr); 117 exit(EXIT_FAILURE); 118 } 119 process_pending_signals(env); 120 } 121 } 122 123 void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs) 124 { 125 int i; 126 127 for (i = 0; i < 32; i++) { 128 env->gpr[i] = regs->regs[i]; 129 } 130 env->pc = regs->csr.era; 131 132 } 133