master
c 131 lines 4.01 KB
Raw
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 CPUSysState *sys = env_sys(env);
23 CPUState *cs = env_cpu(env);
24 int trapnr, si_code;
25 abi_long ret;
26
27 for (;;) {
28 cpu_exec_start(cs);
29 trapnr = cpu_exec(cs);
30 cpu_exec_end(cs);
31 qemu_process_cpu_events(cs);
32
33 switch (trapnr) {
34 case EXCP_INTERRUPT:
35 /* just indicate that signals should be handled asap */
36 break;
37 case EXCCODE_SYS:
38 env->pc += 4;
39 ret = do_syscall(env, env->gpr[11],
40 env->gpr[4], env->gpr[5],
41 env->gpr[6], env->gpr[7],
42 env->gpr[8], env->gpr[9],
43 -1, -1);
44 if (ret == -QEMU_ERESTARTSYS) {
45 env->pc -= 4;
46 break;
47 }
48 if (ret == -QEMU_ESIGRETURN || ret == -QEMU_ESETPC) {
49 /*
50 * Returning from a successful sigreturn syscall or from
51 * control flow diversion in a plugin callback.
52 * Avoid clobbering register state.
53 */
54 break;
55 }
56 env->gpr[4] = ret;
57 break;
58 case EXCCODE_INE:
59 force_sig_fault(TARGET_SIGILL, 0, env->pc);
60 break;
61 case EXCCODE_FPE:
62 si_code = TARGET_FPE_FLTUNK;
63 if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) {
64 si_code = TARGET_FPE_FLTINV;
65 } else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) {
66 si_code = TARGET_FPE_FLTDIV;
67 } else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) {
68 si_code = TARGET_FPE_FLTOVF;
69 } else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) {
70 si_code = TARGET_FPE_FLTUND;
71 } else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) {
72 si_code = TARGET_FPE_FLTRES;
73 }
74 force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
75 break;
76 case EXCP_DEBUG:
77 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
78 break;
79 case EXCCODE_BRK:
80 {
81 unsigned int opcode;
82
83 get_user_u32(opcode, env->pc);
84
85 switch (opcode & 0x7fff) {
86 case BRK_OVERFLOW:
87 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
88 break;
89 case BRK_DIVZERO:
90 force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
91 break;
92 default:
93 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
94 }
95 }
96 break;
97 case EXCCODE_BCE:
98 force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
99 break;
100
101 /*
102 * Begin with LSX and LASX disabled, then enable on the first trap.
103 * In this way we can tell if the unit is in use. This is used to
104 * choose the layout of any signal frame.
105 */
106 case EXCCODE_SXD:
107 sys->CSR_EUEN |= R_CSR_EUEN_SXE_MASK;
108 break;
109 case EXCCODE_ASXD:
110 sys->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK;
111 break;
112
113 case EXCP_ATOMIC:
114 cpu_exec_step_atomic(cs);
115 break;
116 default:
117 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n",
118 trapnr);
119 exit(EXIT_FAILURE);
120 }
121 process_pending_signals(env);
122 }
123 }
124
125 void init_main_thread(CPUState *cs, struct image_info *info)
126 {
127 CPUArchState *env = cpu_env(cs);
128
129 env->pc = info->entry;
130 env->gpr[3] = info->start_stack;
131 }