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