master
c 256 lines 9.26 KB
Raw
1 /*
2 * qemu user cpu loop
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "qemu.h"
22 #include "user-internals.h"
23 #include "user/cpu_loop.h"
24 #include "signal-common.h"
25 #include "qemu/guest-random.h"
26 #include "semihosting/common-semi.h"
27 #include "target/arm/syndrome.h"
28 #include "target/arm/cpu-features.h"
29
30 /* Use the exception syndrome to map a cpu exception to a signal. */
31 static void signal_for_exception(CPUARMState *env, vaddr addr)
32 {
33 uint32_t syn = env->exception.syndrome;
34 int si_code, si_signo;
35
36 /* Let signal delivery see that ESR is live. */
37 env->cp15.esr_el[1] = syn;
38
39 switch (syn_get_ec(syn)) {
40 case EC_DATAABORT:
41 case EC_INSNABORT:
42 /* Both EC have the same format for FSC, or close enough. */
43 switch (extract32(syn, 0, 6)) {
44 case 0x04 ... 0x07: /* Translation fault, level {0-3} */
45 si_signo = TARGET_SIGSEGV;
46 si_code = TARGET_SEGV_MAPERR;
47 break;
48 case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
49 case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
50 si_signo = TARGET_SIGSEGV;
51 si_code = TARGET_SEGV_ACCERR;
52 break;
53 case 0x11: /* Synchronous Tag Check Fault */
54 si_signo = TARGET_SIGSEGV;
55 si_code = TARGET_SEGV_MTESERR;
56 break;
57 case 0x21: /* Alignment fault */
58 si_signo = TARGET_SIGBUS;
59 si_code = TARGET_BUS_ADRALN;
60 break;
61 default:
62 g_assert_not_reached();
63 }
64 break;
65
66 case EC_PCALIGNMENT:
67 si_signo = TARGET_SIGBUS;
68 si_code = TARGET_BUS_ADRALN;
69 break;
70
71 case EC_UNCATEGORIZED: /* E.g. undefined instruction */
72 case EC_SYSTEMREGISTERTRAP: /* E.g. inaccessible register */
73 case EC_SMETRAP: /* E.g. invalid insn in streaming state */
74 case EC_BTITRAP: /* E.g. invalid guarded branch target */
75 case EC_ILLEGALSTATE:
76 /*
77 * Illegal state happens via an ERET from a privileged mode,
78 * so is not normally possible from user-only. However, gdbstub
79 * is not prevented from writing CPSR_IL, aka PSTATE.IL, which
80 * would generate a trap from the next translated block.
81 * In the kernel, default case -> el0_inv -> bad_el0_sync.
82 */
83 si_signo = TARGET_SIGILL;
84 si_code = TARGET_ILL_ILLOPC;
85 break;
86
87 case EC_PACFAIL:
88 si_signo = TARGET_SIGILL;
89 si_code = TARGET_ILL_ILLOPN;
90 break;
91
92 case EC_GCS:
93 si_signo = TARGET_SIGSEGV;
94 si_code = TARGET_SEGV_CPERR;
95 break;
96
97 case EC_MOP:
98 /*
99 * FIXME: The kernel fixes up wrong-option exceptions.
100 * For QEMU linux-user mode, you can only get these if
101 * the process is doing something silly (not executing
102 * the MOPS instructions in the required P/M/E sequence),
103 * so it is not a problem in practice that we do not.
104 *
105 * We ought ideally to implement the same "rewind to the
106 * start of the sequence" logic that the kernel does in
107 * arm64_mops_reset_regs(). In the meantime, deliver
108 * the guest a SIGILL, with the same ILLOPN si_code
109 * we've always used for this.
110 */
111 si_signo = TARGET_SIGILL;
112 si_code = TARGET_ILL_ILLOPN;
113 break;
114
115 case EC_WFX_TRAP: /* user-only WFI implemented as NOP */
116 case EC_CP15RTTRAP: /* AArch32 */
117 case EC_CP15RRTTRAP: /* AArch32 */
118 case EC_CP14RTTRAP: /* AArch32 */
119 case EC_CP14DTTRAP: /* AArch32 */
120 case EC_ADVSIMDFPACCESSTRAP: /* user-only does not disable fpu */
121 case EC_FPIDTRAP: /* AArch32 */
122 case EC_PACTRAP: /* user-only does not disable pac regs */
123 case EC_BXJTRAP: /* AArch32 */
124 case EC_CP14RRTTRAP: /* AArch32 */
125 case EC_AA32_SVC: /* AArch32 */
126 case EC_AA32_HVC: /* AArch32 */
127 case EC_AA32_SMC: /* AArch32 */
128 case EC_AA64_SVC: /* generates EXCP_SWI */
129 case EC_AA64_HVC: /* user-only generates EC_UNCATEGORIZED */
130 case EC_AA64_SMC: /* user-only generates EC_UNCATEGORIZED */
131 case EC_SVEACCESSTRAP: /* user-only does not disable sve */
132 case EC_ERETTRAP: /* user-only generates EC_UNCATEGORIZED */
133 case EC_GPC: /* user-only has no EL3 gpc tables */
134 case EC_INSNABORT_SAME_EL: /* el0 cannot trap to el0 */
135 case EC_DATAABORT_SAME_EL: /* el0 cannot trap to el0 */
136 case EC_SPALIGNMENT: /* sp alignment checks not implemented */
137 case EC_AA32_FPTRAP: /* fp exceptions not implemented */
138 case EC_AA64_FPTRAP: /* fp exceptions not implemented */
139 case EC_SERROR: /* user-only does not have hw faults */
140 case EC_BREAKPOINT: /* user-only does not have hw debug */
141 case EC_BREAKPOINT_SAME_EL: /* user-only does not have hw debug */
142 case EC_SOFTWARESTEP: /* user-only does not have hw debug */
143 case EC_SOFTWARESTEP_SAME_EL: /* user-only does not have hw debug */
144 case EC_WATCHPOINT: /* user-only does not have hw debug */
145 case EC_WATCHPOINT_SAME_EL: /* user-only does not have hw debug */
146 case EC_AA32_BKPT: /* AArch32 */
147 case EC_VECTORCATCH: /* AArch32 */
148 case EC_AA64_BKPT: /* generates EXCP_BKPT */
149 default:
150 g_assert_not_reached();
151 }
152
153 force_sig_fault(si_signo, si_code, addr);
154 }
155
156 /* AArch64 main loop */
157 void cpu_loop(CPUARMState *env)
158 {
159 CPUState *cs = env_cpu(env);
160 int trapnr;
161 abi_long ret;
162
163 for (;;) {
164 cpu_exec_start(cs);
165 trapnr = cpu_exec(cs);
166 cpu_exec_end(cs);
167 qemu_process_cpu_events(cs);
168
169 switch (trapnr) {
170 case EXCP_SWI:
171 /* On syscall, PSTATE.ZA is preserved, PSTATE.SM is cleared. */
172 aarch64_set_svcr(env, 0, R_SVCR_SM_MASK);
173 ret = do_syscall(env,
174 env->xregs[8],
175 env->xregs[0],
176 env->xregs[1],
177 env->xregs[2],
178 env->xregs[3],
179 env->xregs[4],
180 env->xregs[5],
181 0, 0);
182 if (ret == -QEMU_ERESTARTSYS) {
183 env->pc -= 4;
184 } else if (ret != -QEMU_ESIGRETURN && ret != -QEMU_ESETPC) {
185 env->xregs[0] = ret;
186 }
187 break;
188 case EXCP_INTERRUPT:
189 /* just indicate that signals should be handled asap */
190 break;
191 case EXCP_UDEF:
192 signal_for_exception(env, env->pc);
193 break;
194 case EXCP_PREFETCH_ABORT:
195 case EXCP_DATA_ABORT:
196 signal_for_exception(env, env->exception.vaddress);
197 break;
198 case EXCP_DEBUG:
199 case EXCP_BKPT:
200 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
201 break;
202 case EXCP_SEMIHOST:
203 do_common_semihosting(cs);
204 env->pc += 4;
205 break;
206 case EXCP_YIELD:
207 /* nothing to do here for user-mode, just resume guest code */
208 break;
209 case EXCP_ATOMIC:
210 cpu_exec_step_atomic(cs);
211 break;
212 default:
213 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
214 abort();
215 }
216
217 /* Check for MTE asynchronous faults */
218 if (unlikely(env->cp15.tfsr_el[0])) {
219 env->cp15.tfsr_el[0] = 0;
220 force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MTEAERR, 0);
221 }
222
223 process_pending_signals(env);
224 /* Exception return on AArch64 always clears the exclusive monitor,
225 * so any return to running guest code implies this.
226 */
227 env->exclusive_addr = -1;
228 }
229 }
230
231 void init_main_thread(CPUState *cs, struct image_info *info)
232 {
233 CPUARMState *env = cpu_env(cs);
234 ARMCPU *cpu = env_archcpu(env);
235
236 if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
237 fprintf(stderr,
238 "The selected ARM CPU does not support 64 bit mode\n");
239 exit(EXIT_FAILURE);
240 }
241
242 env->pc = info->entry & ~0x3ULL;
243 env->xregs[31] = info->start_stack;
244
245 #if TARGET_BIG_ENDIAN
246 env->cp15.sctlr_el[1] |= SCTLR_E0E;
247 for (int i = 1; i < 4; ++i) {
248 env->cp15.sctlr_el[i] |= SCTLR_EE;
249 }
250 arm_rebuild_hflags(env);
251 #endif
252
253 if (cpu_isar_feature(aa64_pauth, cpu)) {
254 qemu_guest_getrandom_nofail(&env->keys, sizeof(env->keys));
255 }
256 }