xref: /qemu/linux-user/loongarch64/cpu_loop.c (revision a9d3d1dff6f9e1544e8a84e74645b8e4fe08c0ad)
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