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