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