| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * QEMU LoongArch user cpu_loop. |
| * |
| * Copyright (c) 2021 Loongson Technology Corporation Limited |
| */ |
| |
| #include "qemu/osdep.h" |
| #include "qemu.h" |
| #include "user-internals.h" |
| #include "cpu_loop-common.h" |
| #include "signal-common.h" |
| |
| void cpu_loop(CPULoongArchState *env) |
| { |
| CPUState *cs = env_cpu(env); |
| int trapnr, si_code; |
| abi_long ret; |
| |
| for (;;) { |
| cpu_exec_start(cs); |
| trapnr = cpu_exec(cs); |
| cpu_exec_end(cs); |
| process_queued_cpu_work(cs); |
| |
| switch (trapnr) { |
| case EXCP_INTERRUPT: |
| /* just indicate that signals should be handled asap */ |
| break; |
| case EXCCODE_SYS: |
| env->pc += 4; |
| ret = do_syscall(env, env->gpr[11], |
| env->gpr[4], env->gpr[5], |
| env->gpr[6], env->gpr[7], |
| env->gpr[8], env->gpr[9], |
| -1, -1); |
| if (ret == -QEMU_ERESTARTSYS) { |
| env->pc -= 4; |
| break; |
| } |
| if (ret == -QEMU_ESIGRETURN) { |
| /* |
| * Returning from a successful sigreturn syscall. |
| * Avoid clobbering register state. |
| */ |
| break; |
| } |
| env->gpr[4] = ret; |
| break; |
| case EXCCODE_INE: |
| force_sig_fault(TARGET_SIGILL, 0, env->pc); |
| break; |
| case EXCCODE_FPE: |
| si_code = TARGET_FPE_FLTUNK; |
| if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { |
| si_code = TARGET_FPE_FLTINV; |
| } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) { |
| si_code = TARGET_FPE_FLTDIV; |
| } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) { |
| si_code = TARGET_FPE_FLTOVF; |
| } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) { |
| si_code = TARGET_FPE_FLTUND; |
| } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) { |
| si_code = TARGET_FPE_FLTRES; |
| } |
| force_sig_fault(TARGET_SIGFPE, si_code, env->pc); |
| break; |
| case EXCP_DEBUG: |
| case EXCCODE_BRK: |
| force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); |
| break; |
| case EXCCODE_BCE: |
| force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc); |
| break; |
| |
| /* |
| * Begin with LSX and LASX disabled, then enable on the first trap. |
| * In this way we can tell if the unit is in use. This is used to |
| * choose the layout of any signal frame. |
| */ |
| case EXCCODE_SXD: |
| env->CSR_EUEN |= R_CSR_EUEN_SXE_MASK; |
| break; |
| case EXCCODE_ASXD: |
| env->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK; |
| break; |
| |
| case EXCP_ATOMIC: |
| cpu_exec_step_atomic(cs); |
| break; |
| default: |
| EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", |
| trapnr); |
| exit(EXIT_FAILURE); |
| } |
| process_pending_signals(env); |
| } |
| } |
| |
| void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) |
| { |
| int i; |
| |
| for (i = 0; i < 32; i++) { |
| env->gpr[i] = regs->regs[i]; |
| } |
| env->pc = regs->csr.era; |
| |
| } |