Merge tag 'pull-request-2022-09-28' of https://gitlab.com/thuth/qemu into staging
[qemu.git] / linux-user / arm / cpu_loop.c
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-common.h"
22 #include "qemu.h"
23 #include "user-internals.h"
24 #include "elf.h"
25 #include "cpu_loop-common.h"
26 #include "signal-common.h"
27 #include "semihosting/common-semi.h"
28 #include "target/arm/syndrome.h"
29
30 #define get_user_code_u32(x, gaddr, env) \
31 ({ abi_long __r = get_user_u32((x), (gaddr)); \
32 if (!__r && bswap_code(arm_sctlr_b(env))) { \
33 (x) = bswap32(x); \
34 } \
35 __r; \
36 })
37
38 #define get_user_code_u16(x, gaddr, env) \
39 ({ abi_long __r = get_user_u16((x), (gaddr)); \
40 if (!__r && bswap_code(arm_sctlr_b(env))) { \
41 (x) = bswap16(x); \
42 } \
43 __r; \
44 })
45
46 #define get_user_data_u32(x, gaddr, env) \
47 ({ abi_long __r = get_user_u32((x), (gaddr)); \
48 if (!__r && arm_cpu_bswap_data(env)) { \
49 (x) = bswap32(x); \
50 } \
51 __r; \
52 })
53
54 #define get_user_data_u16(x, gaddr, env) \
55 ({ abi_long __r = get_user_u16((x), (gaddr)); \
56 if (!__r && arm_cpu_bswap_data(env)) { \
57 (x) = bswap16(x); \
58 } \
59 __r; \
60 })
61
62 #define put_user_data_u32(x, gaddr, env) \
63 ({ typeof(x) __x = (x); \
64 if (arm_cpu_bswap_data(env)) { \
65 __x = bswap32(__x); \
66 } \
67 put_user_u32(__x, (gaddr)); \
68 })
69
70 #define put_user_data_u16(x, gaddr, env) \
71 ({ typeof(x) __x = (x); \
72 if (arm_cpu_bswap_data(env)) { \
73 __x = bswap16(__x); \
74 } \
75 put_user_u16(__x, (gaddr)); \
76 })
77
78 /* Commpage handling -- there is no commpage for AArch64 */
79
80 /*
81 * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
82 * Input:
83 * r0 = pointer to oldval
84 * r1 = pointer to newval
85 * r2 = pointer to target value
86 *
87 * Output:
88 * r0 = 0 if *ptr was changed, non-0 if no exchange happened
89 * C set if *ptr was changed, clear if no exchange happened
90 *
91 * Note segv's in kernel helpers are a bit tricky, we can set the
92 * data address sensibly but the PC address is just the entry point.
93 */
94 static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
95 {
96 uint64_t oldval, newval, val;
97 uint32_t addr, cpsr;
98
99 /* Based on the 32 bit code in do_kernel_trap */
100
101 /* XXX: This only works between threads, not between processes.
102 It's probably possible to implement this with native host
103 operations. However things like ldrex/strex are much harder so
104 there's not much point trying. */
105 start_exclusive();
106 cpsr = cpsr_read(env);
107 addr = env->regs[2];
108
109 if (get_user_u64(oldval, env->regs[0])) {
110 env->exception.vaddress = env->regs[0];
111 goto segv;
112 };
113
114 if (get_user_u64(newval, env->regs[1])) {
115 env->exception.vaddress = env->regs[1];
116 goto segv;
117 };
118
119 if (get_user_u64(val, addr)) {
120 env->exception.vaddress = addr;
121 goto segv;
122 }
123
124 if (val == oldval) {
125 val = newval;
126
127 if (put_user_u64(val, addr)) {
128 env->exception.vaddress = addr;
129 goto segv;
130 };
131
132 env->regs[0] = 0;
133 cpsr |= CPSR_C;
134 } else {
135 env->regs[0] = -1;
136 cpsr &= ~CPSR_C;
137 }
138 cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
139 end_exclusive();
140 return;
141
142 segv:
143 end_exclusive();
144 /* We get the PC of the entry address - which is as good as anything,
145 on a real kernel what you get depends on which mode it uses. */
146 /* XXX: check env->error_code */
147 force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
148 env->exception.vaddress);
149 }
150
151 /* Handle a jump to the kernel code page. */
152 static int
153 do_kernel_trap(CPUARMState *env)
154 {
155 uint32_t addr;
156 uint32_t cpsr;
157 uint32_t val;
158
159 switch (env->regs[15]) {
160 case 0xffff0fa0: /* __kernel_memory_barrier */
161 /* ??? No-op. Will need to do better for SMP. */
162 break;
163 case 0xffff0fc0: /* __kernel_cmpxchg */
164 /* XXX: This only works between threads, not between processes.
165 It's probably possible to implement this with native host
166 operations. However things like ldrex/strex are much harder so
167 there's not much point trying. */
168 start_exclusive();
169 cpsr = cpsr_read(env);
170 addr = env->regs[2];
171 /* FIXME: This should SEGV if the access fails. */
172 if (get_user_u32(val, addr))
173 val = ~env->regs[0];
174 if (val == env->regs[0]) {
175 val = env->regs[1];
176 /* FIXME: Check for segfaults. */
177 put_user_u32(val, addr);
178 env->regs[0] = 0;
179 cpsr |= CPSR_C;
180 } else {
181 env->regs[0] = -1;
182 cpsr &= ~CPSR_C;
183 }
184 cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
185 end_exclusive();
186 break;
187 case 0xffff0fe0: /* __kernel_get_tls */
188 env->regs[0] = cpu_get_tls(env);
189 break;
190 case 0xffff0f60: /* __kernel_cmpxchg64 */
191 arm_kernel_cmpxchg64_helper(env);
192 break;
193
194 default:
195 return 1;
196 }
197 /* Jump back to the caller. */
198 addr = env->regs[14];
199 if (addr & 1) {
200 env->thumb = 1;
201 addr &= ~1;
202 }
203 env->regs[15] = addr;
204
205 return 0;
206 }
207
208 static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb)
209 {
210 /*
211 * Return true if this insn is one of the three magic UDF insns
212 * which the kernel treats as breakpoint insns.
213 */
214 if (!is_thumb) {
215 return (opcode & 0x0fffffff) == 0x07f001f0;
216 } else {
217 /*
218 * Note that we get the two halves of the 32-bit T32 insn
219 * in the opposite order to the value the kernel uses in
220 * its undef_hook struct.
221 */
222 return ((opcode & 0xffff) == 0xde01) || (opcode == 0xa000f7f0);
223 }
224 }
225
226 static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
227 {
228 TaskState *ts = env_cpu(env)->opaque;
229 int rc = EmulateAll(opcode, &ts->fpa, env);
230 int raise, enabled;
231
232 if (rc == 0) {
233 /* Illegal instruction */
234 return false;
235 }
236 if (rc > 0) {
237 /* Everything ok. */
238 env->regs[15] += 4;
239 return true;
240 }
241
242 /* FP exception */
243 rc = -rc;
244 raise = 0;
245
246 /* Translate softfloat flags to FPSR flags */
247 if (rc & float_flag_invalid) {
248 raise |= BIT_IOC;
249 }
250 if (rc & float_flag_divbyzero) {
251 raise |= BIT_DZC;
252 }
253 if (rc & float_flag_overflow) {
254 raise |= BIT_OFC;
255 }
256 if (rc & float_flag_underflow) {
257 raise |= BIT_UFC;
258 }
259 if (rc & float_flag_inexact) {
260 raise |= BIT_IXC;
261 }
262
263 /* Accumulate unenabled exceptions */
264 enabled = ts->fpa.fpsr >> 16;
265 ts->fpa.fpsr |= raise & ~enabled;
266
267 if (raise & enabled) {
268 /*
269 * The kernel's nwfpe emulator does not pass a real si_code.
270 * It merely uses send_sig(SIGFPE, current, 1), which results in
271 * __send_signal() filling out SI_KERNEL with pid and uid 0 (under
272 * the "SEND_SIG_PRIV" case). That's what our force_sig() does.
273 */
274 force_sig(TARGET_SIGFPE);
275 } else {
276 env->regs[15] += 4;
277 }
278 return true;
279 }
280
281 void cpu_loop(CPUARMState *env)
282 {
283 CPUState *cs = env_cpu(env);
284 int trapnr, si_signo, si_code;
285 unsigned int n, insn;
286 abi_ulong ret;
287
288 for(;;) {
289 cpu_exec_start(cs);
290 trapnr = cpu_exec(cs);
291 cpu_exec_end(cs);
292 process_queued_cpu_work(cs);
293
294 switch(trapnr) {
295 case EXCP_UDEF:
296 case EXCP_NOCP:
297 case EXCP_INVSTATE:
298 {
299 uint32_t opcode;
300
301 /* we handle the FPU emulation here, as Linux */
302 /* we get the opcode */
303 /* FIXME - what to do if get_user() fails? */
304 get_user_code_u32(opcode, env->regs[15], env);
305
306 /*
307 * The Linux kernel treats some UDF patterns specially
308 * to use as breakpoints (instead of the architectural
309 * bkpt insn). These should trigger a SIGTRAP rather
310 * than SIGILL.
311 */
312 if (insn_is_linux_bkpt(opcode, env->thumb)) {
313 goto excp_debug;
314 }
315
316 if (!env->thumb && emulate_arm_fpa11(env, opcode)) {
317 break;
318 }
319
320 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN,
321 env->regs[15]);
322 }
323 break;
324 case EXCP_SWI:
325 {
326 env->eabi = 1;
327 /* system call */
328 if (env->thumb) {
329 /* Thumb is always EABI style with syscall number in r7 */
330 n = env->regs[7];
331 } else {
332 /*
333 * Equivalent of kernel CONFIG_OABI_COMPAT: read the
334 * Arm SVC insn to extract the immediate, which is the
335 * syscall number in OABI.
336 */
337 /* FIXME - what to do if get_user() fails? */
338 get_user_code_u32(insn, env->regs[15] - 4, env);
339 n = insn & 0xffffff;
340 if (n == 0) {
341 /* zero immediate: EABI, syscall number in r7 */
342 n = env->regs[7];
343 } else {
344 /*
345 * This XOR matches the kernel code: an immediate
346 * in the valid range (0x900000 .. 0x9fffff) is
347 * converted into the correct EABI-style syscall
348 * number; invalid immediates end up as values
349 * > 0xfffff and are handled below as out-of-range.
350 */
351 n ^= ARM_SYSCALL_BASE;
352 env->eabi = 0;
353 }
354 }
355
356 if (n > ARM_NR_BASE) {
357 switch (n) {
358 case ARM_NR_cacheflush:
359 /* nop */
360 break;
361 case ARM_NR_set_tls:
362 cpu_set_tls(env, env->regs[0]);
363 env->regs[0] = 0;
364 break;
365 case ARM_NR_breakpoint:
366 env->regs[15] -= env->thumb ? 2 : 4;
367 goto excp_debug;
368 case ARM_NR_get_tls:
369 env->regs[0] = cpu_get_tls(env);
370 break;
371 default:
372 if (n < 0xf0800) {
373 /*
374 * Syscalls 0xf0000..0xf07ff (or 0x9f0000..
375 * 0x9f07ff in OABI numbering) are defined
376 * to return -ENOSYS rather than raising
377 * SIGILL. Note that we have already
378 * removed the 0x900000 prefix.
379 */
380 qemu_log_mask(LOG_UNIMP,
381 "qemu: Unsupported ARM syscall: 0x%x\n",
382 n);
383 env->regs[0] = -TARGET_ENOSYS;
384 } else {
385 /*
386 * Otherwise SIGILL. This includes any SWI with
387 * immediate not originally 0x9fxxxx, because
388 * of the earlier XOR.
389 * Like the real kernel, we report the addr of the
390 * SWI in the siginfo si_addr but leave the PC
391 * pointing at the insn after the SWI.
392 */
393 abi_ulong faultaddr = env->regs[15];
394 faultaddr -= env->thumb ? 2 : 4;
395 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP,
396 faultaddr);
397 }
398 break;
399 }
400 } else {
401 ret = do_syscall(env,
402 n,
403 env->regs[0],
404 env->regs[1],
405 env->regs[2],
406 env->regs[3],
407 env->regs[4],
408 env->regs[5],
409 0, 0);
410 if (ret == -QEMU_ERESTARTSYS) {
411 env->regs[15] -= env->thumb ? 2 : 4;
412 } else if (ret != -QEMU_ESIGRETURN) {
413 env->regs[0] = ret;
414 }
415 }
416 }
417 break;
418 case EXCP_SEMIHOST:
419 env->regs[0] = do_common_semihosting(cs);
420 env->regs[15] += env->thumb ? 2 : 4;
421 break;
422 case EXCP_INTERRUPT:
423 /* just indicate that signals should be handled asap */
424 break;
425 case EXCP_PREFETCH_ABORT:
426 case EXCP_DATA_ABORT:
427 /* For user-only we don't set TTBCR_EAE, so look at the FSR. */
428 switch (env->exception.fsr & 0x1f) {
429 case 0x1: /* Alignment */
430 si_signo = TARGET_SIGBUS;
431 si_code = TARGET_BUS_ADRALN;
432 break;
433 case 0x3: /* Access flag fault, level 1 */
434 case 0x6: /* Access flag fault, level 2 */
435 case 0x9: /* Domain fault, level 1 */
436 case 0xb: /* Domain fault, level 2 */
437 case 0xd: /* Permision fault, level 1 */
438 case 0xf: /* Permision fault, level 2 */
439 si_signo = TARGET_SIGSEGV;
440 si_code = TARGET_SEGV_ACCERR;
441 break;
442 case 0x5: /* Translation fault, level 1 */
443 case 0x7: /* Translation fault, level 2 */
444 si_signo = TARGET_SIGSEGV;
445 si_code = TARGET_SEGV_MAPERR;
446 break;
447 default:
448 g_assert_not_reached();
449 }
450 force_sig_fault(si_signo, si_code, env->exception.vaddress);
451 break;
452 case EXCP_DEBUG:
453 case EXCP_BKPT:
454 excp_debug:
455 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]);
456 break;
457 case EXCP_KERNEL_TRAP:
458 if (do_kernel_trap(env))
459 goto error;
460 break;
461 case EXCP_YIELD:
462 /* nothing to do here for user-mode, just resume guest code */
463 break;
464 case EXCP_ATOMIC:
465 cpu_exec_step_atomic(cs);
466 break;
467 default:
468 error:
469 EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
470 abort();
471 }
472 process_pending_signals(env);
473 }
474 }
475
476 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
477 {
478 CPUState *cpu = env_cpu(env);
479 TaskState *ts = cpu->opaque;
480 struct image_info *info = ts->info;
481 int i;
482
483 cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
484 CPSRWriteByInstr);
485 for(i = 0; i < 16; i++) {
486 env->regs[i] = regs->uregs[i];
487 }
488 #ifdef TARGET_WORDS_BIGENDIAN
489 /* Enable BE8. */
490 if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
491 && (info->elf_flags & EF_ARM_BE8)) {
492 env->uncached_cpsr |= CPSR_E;
493 env->cp15.sctlr_el[1] |= SCTLR_E0E;
494 } else {
495 env->cp15.sctlr_el[1] |= SCTLR_B;
496 }
497 arm_rebuild_hflags(env);
498 #endif
499
500 ts->stack_base = info->start_stack;
501 ts->heap_base = info->brk;
502 /* This will be filled in on the first SYS_HEAPINFO call. */
503 ts->heap_limit = 0;
504 }