xref: /openbmc/qemu/linux-user/arm/cpu_loop.c (revision 873f9ca3857cfeeef45441b116c91156736d529c)
1cd71c089SLaurent Vivier /*
2cd71c089SLaurent Vivier  *  qemu user cpu loop
3cd71c089SLaurent Vivier  *
4cd71c089SLaurent Vivier  *  Copyright (c) 2003-2008 Fabrice Bellard
5cd71c089SLaurent Vivier  *
6cd71c089SLaurent Vivier  *  This program is free software; you can redistribute it and/or modify
7cd71c089SLaurent Vivier  *  it under the terms of the GNU General Public License as published by
8cd71c089SLaurent Vivier  *  the Free Software Foundation; either version 2 of the License, or
9cd71c089SLaurent Vivier  *  (at your option) any later version.
10cd71c089SLaurent Vivier  *
11cd71c089SLaurent Vivier  *  This program is distributed in the hope that it will be useful,
12cd71c089SLaurent Vivier  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13cd71c089SLaurent Vivier  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14cd71c089SLaurent Vivier  *  GNU General Public License for more details.
15cd71c089SLaurent Vivier  *
16cd71c089SLaurent Vivier  *  You should have received a copy of the GNU General Public License
17cd71c089SLaurent Vivier  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18cd71c089SLaurent Vivier  */
19cd71c089SLaurent Vivier 
20cd71c089SLaurent Vivier #include "qemu/osdep.h"
21cd71c089SLaurent Vivier #include "qemu.h"
223b249d26SPeter Maydell #include "user-internals.h"
23d9673512SLaurent Vivier #include "elf.h"
24cd71c089SLaurent Vivier #include "cpu_loop-common.h"
252113aed6SPeter Maydell #include "signal-common.h"
266b5fe137SPhilippe Mathieu-Daudé #include "semihosting/common-semi.h"
27*74781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
2839a099caSRichard Henderson #include "target/arm/syndrome.h"
29cd71c089SLaurent Vivier 
30d9673512SLaurent Vivier #define get_user_code_u32(x, gaddr, env)                \
31d9673512SLaurent Vivier     ({ abi_long __r = get_user_u32((x), (gaddr));       \
32d9673512SLaurent Vivier         if (!__r && bswap_code(arm_sctlr_b(env))) {     \
33d9673512SLaurent Vivier             (x) = bswap32(x);                           \
34d9673512SLaurent Vivier         }                                               \
35d9673512SLaurent Vivier         __r;                                            \
36d9673512SLaurent Vivier     })
37d9673512SLaurent Vivier 
38d9673512SLaurent Vivier #define get_user_code_u16(x, gaddr, env)                \
39d9673512SLaurent Vivier     ({ abi_long __r = get_user_u16((x), (gaddr));       \
40d9673512SLaurent Vivier         if (!__r && bswap_code(arm_sctlr_b(env))) {     \
41d9673512SLaurent Vivier             (x) = bswap16(x);                           \
42d9673512SLaurent Vivier         }                                               \
43d9673512SLaurent Vivier         __r;                                            \
44d9673512SLaurent Vivier     })
45d9673512SLaurent Vivier 
46d9673512SLaurent Vivier #define get_user_data_u32(x, gaddr, env)                \
47d9673512SLaurent Vivier     ({ abi_long __r = get_user_u32((x), (gaddr));       \
48d9673512SLaurent Vivier         if (!__r && arm_cpu_bswap_data(env)) {          \
49d9673512SLaurent Vivier             (x) = bswap32(x);                           \
50d9673512SLaurent Vivier         }                                               \
51d9673512SLaurent Vivier         __r;                                            \
52d9673512SLaurent Vivier     })
53d9673512SLaurent Vivier 
54d9673512SLaurent Vivier #define get_user_data_u16(x, gaddr, env)                \
55d9673512SLaurent Vivier     ({ abi_long __r = get_user_u16((x), (gaddr));       \
56d9673512SLaurent Vivier         if (!__r && arm_cpu_bswap_data(env)) {          \
57d9673512SLaurent Vivier             (x) = bswap16(x);                           \
58d9673512SLaurent Vivier         }                                               \
59d9673512SLaurent Vivier         __r;                                            \
60d9673512SLaurent Vivier     })
61d9673512SLaurent Vivier 
62d9673512SLaurent Vivier #define put_user_data_u32(x, gaddr, env)                \
63d9673512SLaurent Vivier     ({ typeof(x) __x = (x);                             \
64d9673512SLaurent Vivier         if (arm_cpu_bswap_data(env)) {                  \
65d9673512SLaurent Vivier             __x = bswap32(__x);                         \
66d9673512SLaurent Vivier         }                                               \
67d9673512SLaurent Vivier         put_user_u32(__x, (gaddr));                     \
68d9673512SLaurent Vivier     })
69d9673512SLaurent Vivier 
70d9673512SLaurent Vivier #define put_user_data_u16(x, gaddr, env)                \
71d9673512SLaurent Vivier     ({ typeof(x) __x = (x);                             \
72d9673512SLaurent Vivier         if (arm_cpu_bswap_data(env)) {                  \
73d9673512SLaurent Vivier             __x = bswap16(__x);                         \
74d9673512SLaurent Vivier         }                                               \
75d9673512SLaurent Vivier         put_user_u16(__x, (gaddr));                     \
76d9673512SLaurent Vivier     })
77d9673512SLaurent Vivier 
787f4f0d9eSRichard Henderson /*
797f4f0d9eSRichard Henderson  * Similar to code in accel/tcg/user-exec.c, but outside the execution loop.
807f4f0d9eSRichard Henderson  * Must be called with mmap_lock.
817f4f0d9eSRichard Henderson  * We get the PC of the entry address - which is as good as anything,
827f4f0d9eSRichard Henderson  * on a real kernel what you get depends on which mode it uses.
837f4f0d9eSRichard Henderson  */
atomic_mmu_lookup(CPUArchState * env,uint32_t addr,int size)847f4f0d9eSRichard Henderson static void *atomic_mmu_lookup(CPUArchState *env, uint32_t addr, int size)
857f4f0d9eSRichard Henderson {
867f4f0d9eSRichard Henderson     int need_flags = PAGE_READ | PAGE_WRITE_ORG | PAGE_VALID;
877f4f0d9eSRichard Henderson     int page_flags;
887f4f0d9eSRichard Henderson 
897f4f0d9eSRichard Henderson     /* Enforce guest required alignment.  */
907f4f0d9eSRichard Henderson     if (unlikely(addr & (size - 1))) {
917f4f0d9eSRichard Henderson         force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, addr);
927f4f0d9eSRichard Henderson         return NULL;
937f4f0d9eSRichard Henderson     }
947f4f0d9eSRichard Henderson 
957f4f0d9eSRichard Henderson     page_flags = page_get_flags(addr);
967f4f0d9eSRichard Henderson     if (unlikely((page_flags & need_flags) != need_flags)) {
977f4f0d9eSRichard Henderson         force_sig_fault(TARGET_SIGSEGV,
987f4f0d9eSRichard Henderson                         page_flags & PAGE_VALID ?
997f4f0d9eSRichard Henderson                         TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR, addr);
1007f4f0d9eSRichard Henderson         return NULL;
1017f4f0d9eSRichard Henderson     }
1027f4f0d9eSRichard Henderson 
1037f4f0d9eSRichard Henderson     return g2h(env_cpu(env), addr);
1047f4f0d9eSRichard Henderson }
1057f4f0d9eSRichard Henderson 
1067f4f0d9eSRichard Henderson /*
1077f4f0d9eSRichard Henderson  * See the Linux kernel's Documentation/arm/kernel_user_helpers.rst
1087f4f0d9eSRichard Henderson  * Input:
1097f4f0d9eSRichard Henderson  * r0 = oldval
1107f4f0d9eSRichard Henderson  * r1 = newval
1117f4f0d9eSRichard Henderson  * r2 = pointer to target value
1127f4f0d9eSRichard Henderson  *
1137f4f0d9eSRichard Henderson  * Output:
1147f4f0d9eSRichard Henderson  * r0 = 0 if *ptr was changed, non-0 if no exchange happened
1157f4f0d9eSRichard Henderson  * C set if *ptr was changed, clear if no exchange happened
1167f4f0d9eSRichard Henderson  */
arm_kernel_cmpxchg32_helper(CPUARMState * env)1177f4f0d9eSRichard Henderson static void arm_kernel_cmpxchg32_helper(CPUARMState *env)
1187f4f0d9eSRichard Henderson {
1197f4f0d9eSRichard Henderson     uint32_t oldval, newval, val, addr, cpsr, *host_addr;
1207f4f0d9eSRichard Henderson 
12138dd78c4SHelge Deller     /* Swap if host != guest endianness, for the host cmpxchg below */
12238dd78c4SHelge Deller     oldval = tswap32(env->regs[0]);
12338dd78c4SHelge Deller     newval = tswap32(env->regs[1]);
1247f4f0d9eSRichard Henderson     addr = env->regs[2];
1257f4f0d9eSRichard Henderson 
1267f4f0d9eSRichard Henderson     mmap_lock();
1277f4f0d9eSRichard Henderson     host_addr = atomic_mmu_lookup(env, addr, 4);
1287f4f0d9eSRichard Henderson     if (!host_addr) {
1297f4f0d9eSRichard Henderson         mmap_unlock();
1307f4f0d9eSRichard Henderson         return;
1317f4f0d9eSRichard Henderson     }
1327f4f0d9eSRichard Henderson 
1337f4f0d9eSRichard Henderson     val = qatomic_cmpxchg__nocheck(host_addr, oldval, newval);
1347f4f0d9eSRichard Henderson     mmap_unlock();
1357f4f0d9eSRichard Henderson 
1367f4f0d9eSRichard Henderson     cpsr = (val == oldval) * CPSR_C;
1377f4f0d9eSRichard Henderson     cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
1387f4f0d9eSRichard Henderson     env->regs[0] = cpsr ? 0 : -1;
1397f4f0d9eSRichard Henderson }
140d9673512SLaurent Vivier 
141d9673512SLaurent Vivier /*
142330ea9d1SRichard Henderson  * See the Linux kernel's Documentation/arm/kernel_user_helpers.rst
143d9673512SLaurent Vivier  * Input:
144d9673512SLaurent Vivier  * r0 = pointer to oldval
145d9673512SLaurent Vivier  * r1 = pointer to newval
146d9673512SLaurent Vivier  * r2 = pointer to target value
147d9673512SLaurent Vivier  *
148d9673512SLaurent Vivier  * Output:
149d9673512SLaurent Vivier  * r0 = 0 if *ptr was changed, non-0 if no exchange happened
150d9673512SLaurent Vivier  * C set if *ptr was changed, clear if no exchange happened
151d9673512SLaurent Vivier  *
152d9673512SLaurent Vivier  * Note segv's in kernel helpers are a bit tricky, we can set the
153d9673512SLaurent Vivier  * data address sensibly but the PC address is just the entry point.
154d9673512SLaurent Vivier  */
arm_kernel_cmpxchg64_helper(CPUARMState * env)155d9673512SLaurent Vivier static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
156d9673512SLaurent Vivier {
157d9673512SLaurent Vivier     uint64_t oldval, newval, val;
158d9673512SLaurent Vivier     uint32_t addr, cpsr;
159330ea9d1SRichard Henderson     uint64_t *host_addr;
160d9673512SLaurent Vivier 
161330ea9d1SRichard Henderson     addr = env->regs[0];
162330ea9d1SRichard Henderson     if (get_user_u64(oldval, addr)) {
163330ea9d1SRichard Henderson         goto segv;
164330ea9d1SRichard Henderson     }
165d9673512SLaurent Vivier 
166330ea9d1SRichard Henderson     addr = env->regs[1];
167330ea9d1SRichard Henderson     if (get_user_u64(newval, addr)) {
168330ea9d1SRichard Henderson         goto segv;
169330ea9d1SRichard Henderson     }
170330ea9d1SRichard Henderson 
171330ea9d1SRichard Henderson     mmap_lock();
172d9673512SLaurent Vivier     addr = env->regs[2];
173330ea9d1SRichard Henderson     host_addr = atomic_mmu_lookup(env, addr, 8);
174330ea9d1SRichard Henderson     if (!host_addr) {
175330ea9d1SRichard Henderson         mmap_unlock();
176330ea9d1SRichard Henderson         return;
177d9673512SLaurent Vivier     }
178d9673512SLaurent Vivier 
17938dd78c4SHelge Deller     /* Swap if host != guest endianness, for the host cmpxchg below */
18038dd78c4SHelge Deller     oldval = tswap64(oldval);
18138dd78c4SHelge Deller     newval = tswap64(newval);
18238dd78c4SHelge Deller 
183330ea9d1SRichard Henderson #ifdef CONFIG_ATOMIC64
184330ea9d1SRichard Henderson     val = qatomic_cmpxchg__nocheck(host_addr, oldval, newval);
185330ea9d1SRichard Henderson     cpsr = (val == oldval) * CPSR_C;
186330ea9d1SRichard Henderson #else
187330ea9d1SRichard Henderson     /*
188330ea9d1SRichard Henderson      * This only works between threads, not between processes, but since
189330ea9d1SRichard Henderson      * the host has no 64-bit cmpxchg, it is the best that we can do.
190330ea9d1SRichard Henderson      */
191330ea9d1SRichard Henderson     start_exclusive();
192330ea9d1SRichard Henderson     val = *host_addr;
193d9673512SLaurent Vivier     if (val == oldval) {
194330ea9d1SRichard Henderson         *host_addr = newval;
195330ea9d1SRichard Henderson         cpsr = CPSR_C;
196d9673512SLaurent Vivier     } else {
197330ea9d1SRichard Henderson         cpsr = 0;
198d9673512SLaurent Vivier     }
199d9673512SLaurent Vivier     end_exclusive();
200330ea9d1SRichard Henderson #endif
201330ea9d1SRichard Henderson     mmap_unlock();
202330ea9d1SRichard Henderson 
203330ea9d1SRichard Henderson     cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
204330ea9d1SRichard Henderson     env->regs[0] = cpsr ? 0 : -1;
205d9673512SLaurent Vivier     return;
206d9673512SLaurent Vivier 
207d9673512SLaurent Vivier  segv:
208330ea9d1SRichard Henderson     force_sig_fault(TARGET_SIGSEGV,
209330ea9d1SRichard Henderson                     page_get_flags(addr) & PAGE_VALID ?
210330ea9d1SRichard Henderson                     TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR, addr);
211d9673512SLaurent Vivier }
212d9673512SLaurent Vivier 
213d9673512SLaurent Vivier /* Handle a jump to the kernel code page.  */
214d9673512SLaurent Vivier static int
do_kernel_trap(CPUARMState * env)215d9673512SLaurent Vivier do_kernel_trap(CPUARMState *env)
216d9673512SLaurent Vivier {
217d9673512SLaurent Vivier     uint32_t addr;
218d9673512SLaurent Vivier 
219d9673512SLaurent Vivier     switch (env->regs[15]) {
220d9673512SLaurent Vivier     case 0xffff0fa0: /* __kernel_memory_barrier */
2216e05e704SRichard Henderson         smp_mb();
222d9673512SLaurent Vivier         break;
223d9673512SLaurent Vivier     case 0xffff0fc0: /* __kernel_cmpxchg */
2247f4f0d9eSRichard Henderson         arm_kernel_cmpxchg32_helper(env);
225d9673512SLaurent Vivier         break;
226d9673512SLaurent Vivier     case 0xffff0fe0: /* __kernel_get_tls */
227d9673512SLaurent Vivier         env->regs[0] = cpu_get_tls(env);
228d9673512SLaurent Vivier         break;
229d9673512SLaurent Vivier     case 0xffff0f60: /* __kernel_cmpxchg64 */
230d9673512SLaurent Vivier         arm_kernel_cmpxchg64_helper(env);
231d9673512SLaurent Vivier         break;
232d9673512SLaurent Vivier 
233d9673512SLaurent Vivier     default:
234d9673512SLaurent Vivier         return 1;
235d9673512SLaurent Vivier     }
236d9673512SLaurent Vivier     /* Jump back to the caller.  */
237d9673512SLaurent Vivier     addr = env->regs[14];
238d9673512SLaurent Vivier     if (addr & 1) {
239063bbd80SRichard Henderson         env->thumb = true;
240d9673512SLaurent Vivier         addr &= ~1;
241d9673512SLaurent Vivier     }
242d9673512SLaurent Vivier     env->regs[15] = addr;
243d9673512SLaurent Vivier 
244d9673512SLaurent Vivier     return 0;
245d9673512SLaurent Vivier }
246d9673512SLaurent Vivier 
insn_is_linux_bkpt(uint32_t opcode,bool is_thumb)247acebed94SPeter Maydell static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb)
248acebed94SPeter Maydell {
249acebed94SPeter Maydell     /*
250acebed94SPeter Maydell      * Return true if this insn is one of the three magic UDF insns
251acebed94SPeter Maydell      * which the kernel treats as breakpoint insns.
252acebed94SPeter Maydell      */
253acebed94SPeter Maydell     if (!is_thumb) {
254acebed94SPeter Maydell         return (opcode & 0x0fffffff) == 0x07f001f0;
255acebed94SPeter Maydell     } else {
256acebed94SPeter Maydell         /*
257acebed94SPeter Maydell          * Note that we get the two halves of the 32-bit T32 insn
258acebed94SPeter Maydell          * in the opposite order to the value the kernel uses in
259acebed94SPeter Maydell          * its undef_hook struct.
260acebed94SPeter Maydell          */
261acebed94SPeter Maydell         return ((opcode & 0xffff) == 0xde01) || (opcode == 0xa000f7f0);
262acebed94SPeter Maydell     }
263acebed94SPeter Maydell }
264acebed94SPeter Maydell 
emulate_arm_fpa11(CPUARMState * env,uint32_t opcode)265c1438d6cSRichard Henderson static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
266c1438d6cSRichard Henderson {
267e4e5cb4aSIlya Leoshkevich     TaskState *ts = get_task_state(env_cpu(env));
268c1438d6cSRichard Henderson     int rc = EmulateAll(opcode, &ts->fpa, env);
26974081ae0SRichard Henderson     int raise, enabled;
270c1438d6cSRichard Henderson 
271c1438d6cSRichard Henderson     if (rc == 0) {
272c1438d6cSRichard Henderson         /* Illegal instruction */
273c1438d6cSRichard Henderson         return false;
274c1438d6cSRichard Henderson     }
275c1438d6cSRichard Henderson     if (rc > 0) {
276c1438d6cSRichard Henderson         /* Everything ok. */
277c1438d6cSRichard Henderson         env->regs[15] += 4;
278c1438d6cSRichard Henderson         return true;
279c1438d6cSRichard Henderson     }
280c1438d6cSRichard Henderson 
281c1438d6cSRichard Henderson     /* FP exception */
28274081ae0SRichard Henderson     rc = -rc;
28374081ae0SRichard Henderson     raise = 0;
284c1438d6cSRichard Henderson 
285c1438d6cSRichard Henderson     /* Translate softfloat flags to FPSR flags */
28674081ae0SRichard Henderson     if (rc & float_flag_invalid) {
28774081ae0SRichard Henderson         raise |= BIT_IOC;
288c1438d6cSRichard Henderson     }
28974081ae0SRichard Henderson     if (rc & float_flag_divbyzero) {
29074081ae0SRichard Henderson         raise |= BIT_DZC;
291c1438d6cSRichard Henderson     }
29274081ae0SRichard Henderson     if (rc & float_flag_overflow) {
29374081ae0SRichard Henderson         raise |= BIT_OFC;
294c1438d6cSRichard Henderson     }
29574081ae0SRichard Henderson     if (rc & float_flag_underflow) {
29674081ae0SRichard Henderson         raise |= BIT_UFC;
297c1438d6cSRichard Henderson     }
29874081ae0SRichard Henderson     if (rc & float_flag_inexact) {
29974081ae0SRichard Henderson         raise |= BIT_IXC;
300c1438d6cSRichard Henderson     }
301c1438d6cSRichard Henderson 
30274081ae0SRichard Henderson     /* Accumulate unenabled exceptions */
30374081ae0SRichard Henderson     enabled = ts->fpa.fpsr >> 16;
30474081ae0SRichard Henderson     ts->fpa.fpsr |= raise & ~enabled;
30574081ae0SRichard Henderson 
30674081ae0SRichard Henderson     if (raise & enabled) {
3070a50285eSRichard Henderson         /*
3080a50285eSRichard Henderson          * The kernel's nwfpe emulator does not pass a real si_code.
309babe6d5cSPeter Maydell          * It merely uses send_sig(SIGFPE, current, 1), which results in
310babe6d5cSPeter Maydell          * __send_signal() filling out SI_KERNEL with pid and uid 0 (under
311babe6d5cSPeter Maydell          * the "SEND_SIG_PRIV" case). That's what our force_sig() does.
3120a50285eSRichard Henderson          */
313babe6d5cSPeter Maydell         force_sig(TARGET_SIGFPE);
314c1438d6cSRichard Henderson     } else {
315c1438d6cSRichard Henderson         env->regs[15] += 4;
316c1438d6cSRichard Henderson     }
317c1438d6cSRichard Henderson     return true;
318c1438d6cSRichard Henderson }
319c1438d6cSRichard Henderson 
cpu_loop(CPUARMState * env)320d9673512SLaurent Vivier void cpu_loop(CPUARMState *env)
321d9673512SLaurent Vivier {
3222fc0cc0eSRichard Henderson     CPUState *cs = env_cpu(env);
32339a099caSRichard Henderson     int trapnr, si_signo, si_code;
324d9673512SLaurent Vivier     unsigned int n, insn;
325d9673512SLaurent Vivier     abi_ulong ret;
326d9673512SLaurent Vivier 
327d9673512SLaurent Vivier     for(;;) {
328d9673512SLaurent Vivier         cpu_exec_start(cs);
329d9673512SLaurent Vivier         trapnr = cpu_exec(cs);
330d9673512SLaurent Vivier         cpu_exec_end(cs);
331d9673512SLaurent Vivier         process_queued_cpu_work(cs);
332d9673512SLaurent Vivier 
333d9673512SLaurent Vivier         switch(trapnr) {
334d9673512SLaurent Vivier         case EXCP_UDEF:
335d9673512SLaurent Vivier         case EXCP_NOCP:
336d9673512SLaurent Vivier         case EXCP_INVSTATE:
337d9673512SLaurent Vivier             {
338d9673512SLaurent Vivier                 uint32_t opcode;
339d9673512SLaurent Vivier 
340d9673512SLaurent Vivier                 /* we handle the FPU emulation here, as Linux */
341d9673512SLaurent Vivier                 /* we get the opcode */
342d9673512SLaurent Vivier                 /* FIXME - what to do if get_user() fails? */
343d9673512SLaurent Vivier                 get_user_code_u32(opcode, env->regs[15], env);
344d9673512SLaurent Vivier 
345acebed94SPeter Maydell                 /*
346acebed94SPeter Maydell                  * The Linux kernel treats some UDF patterns specially
347acebed94SPeter Maydell                  * to use as breakpoints (instead of the architectural
348acebed94SPeter Maydell                  * bkpt insn). These should trigger a SIGTRAP rather
349acebed94SPeter Maydell                  * than SIGILL.
350acebed94SPeter Maydell                  */
351acebed94SPeter Maydell                 if (insn_is_linux_bkpt(opcode, env->thumb)) {
352acebed94SPeter Maydell                     goto excp_debug;
353acebed94SPeter Maydell                 }
354acebed94SPeter Maydell 
355d827f6d5SRichard Henderson                 if (!env->thumb && emulate_arm_fpa11(env, opcode)) {
356c1438d6cSRichard Henderson                     break;
357c1438d6cSRichard Henderson                 }
358c1438d6cSRichard Henderson 
3594c90f0baSPeter Maydell                 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN,
3604c90f0baSPeter Maydell                                 env->regs[15]);
361d9673512SLaurent Vivier             }
362d9673512SLaurent Vivier             break;
363d9673512SLaurent Vivier         case EXCP_SWI:
364d9673512SLaurent Vivier             {
365de4143fcSPhilippe Mathieu-Daudé                 env->eabi = true;
366d9673512SLaurent Vivier                 /* system call */
367d9673512SLaurent Vivier                 if (env->thumb) {
3683986a172SPeter Maydell                     /* Thumb is always EABI style with syscall number in r7 */
3693986a172SPeter Maydell                     n = env->regs[7];
370d9673512SLaurent Vivier                 } else {
3713986a172SPeter Maydell                     /*
3723986a172SPeter Maydell                      * Equivalent of kernel CONFIG_OABI_COMPAT: read the
3733986a172SPeter Maydell                      * Arm SVC insn to extract the immediate, which is the
3743986a172SPeter Maydell                      * syscall number in OABI.
3753986a172SPeter Maydell                      */
376d9673512SLaurent Vivier                     /* FIXME - what to do if get_user() fails? */
377d9673512SLaurent Vivier                     get_user_code_u32(insn, env->regs[15] - 4, env);
378d9673512SLaurent Vivier                     n = insn & 0xffffff;
3793986a172SPeter Maydell                     if (n == 0) {
3803986a172SPeter Maydell                         /* zero immediate: EABI, syscall number in r7 */
381d9673512SLaurent Vivier                         n = env->regs[7];
382d9673512SLaurent Vivier                     } else {
3833986a172SPeter Maydell                         /*
3843986a172SPeter Maydell                          * This XOR matches the kernel code: an immediate
3853986a172SPeter Maydell                          * in the valid range (0x900000 .. 0x9fffff) is
3863986a172SPeter Maydell                          * converted into the correct EABI-style syscall
3873986a172SPeter Maydell                          * number; invalid immediates end up as values
3883986a172SPeter Maydell                          * > 0xfffff and are handled below as out-of-range.
3893986a172SPeter Maydell                          */
3903986a172SPeter Maydell                         n ^= ARM_SYSCALL_BASE;
391de4143fcSPhilippe Mathieu-Daudé                         env->eabi = false;
392d9673512SLaurent Vivier                     }
3933986a172SPeter Maydell                 }
3943986a172SPeter Maydell 
395d9673512SLaurent Vivier                 if (n > ARM_NR_BASE) {
396d9673512SLaurent Vivier                     switch (n) {
397d9673512SLaurent Vivier                     case ARM_NR_cacheflush:
398d9673512SLaurent Vivier                         /* nop */
399d9673512SLaurent Vivier                         break;
400d9673512SLaurent Vivier                     case ARM_NR_set_tls:
401d9673512SLaurent Vivier                         cpu_set_tls(env, env->regs[0]);
402d9673512SLaurent Vivier                         env->regs[0] = 0;
403d9673512SLaurent Vivier                         break;
404d9673512SLaurent Vivier                     case ARM_NR_breakpoint:
405d9673512SLaurent Vivier                         env->regs[15] -= env->thumb ? 2 : 4;
406d9673512SLaurent Vivier                         goto excp_debug;
40762aaa514SChristophe Lyon                     case ARM_NR_get_tls:
40862aaa514SChristophe Lyon                         env->regs[0] = cpu_get_tls(env);
40962aaa514SChristophe Lyon                         break;
410d9673512SLaurent Vivier                     default:
411ab546bd2SPeter Maydell                         if (n < 0xf0800) {
412ab546bd2SPeter Maydell                             /*
413ab546bd2SPeter Maydell                              * Syscalls 0xf0000..0xf07ff (or 0x9f0000..
414ab546bd2SPeter Maydell                              * 0x9f07ff in OABI numbering) are defined
415ab546bd2SPeter Maydell                              * to return -ENOSYS rather than raising
416ab546bd2SPeter Maydell                              * SIGILL. Note that we have already
417ab546bd2SPeter Maydell                              * removed the 0x900000 prefix.
418ab546bd2SPeter Maydell                              */
41939be5350SJosh Kunz                             qemu_log_mask(LOG_UNIMP,
42039be5350SJosh Kunz                                 "qemu: Unsupported ARM syscall: 0x%x\n",
421d9673512SLaurent Vivier                                           n);
422d9673512SLaurent Vivier                             env->regs[0] = -TARGET_ENOSYS;
423ab546bd2SPeter Maydell                         } else {
4243986a172SPeter Maydell                             /*
4253986a172SPeter Maydell                              * Otherwise SIGILL. This includes any SWI with
4263986a172SPeter Maydell                              * immediate not originally 0x9fxxxx, because
4273986a172SPeter Maydell                              * of the earlier XOR.
4284c90f0baSPeter Maydell                              * Like the real kernel, we report the addr of the
4294c90f0baSPeter Maydell                              * SWI in the siginfo si_addr but leave the PC
4304c90f0baSPeter Maydell                              * pointing at the insn after the SWI.
4313986a172SPeter Maydell                              */
4324c90f0baSPeter Maydell                             abi_ulong faultaddr = env->regs[15];
4334c90f0baSPeter Maydell                             faultaddr -= env->thumb ? 2 : 4;
4344c90f0baSPeter Maydell                             force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP,
4354c90f0baSPeter Maydell                                             faultaddr);
436ab546bd2SPeter Maydell                         }
437d9673512SLaurent Vivier                         break;
438d9673512SLaurent Vivier                     }
439d9673512SLaurent Vivier                 } else {
440d9673512SLaurent Vivier                     ret = do_syscall(env,
441d9673512SLaurent Vivier                                      n,
442d9673512SLaurent Vivier                                      env->regs[0],
443d9673512SLaurent Vivier                                      env->regs[1],
444d9673512SLaurent Vivier                                      env->regs[2],
445d9673512SLaurent Vivier                                      env->regs[3],
446d9673512SLaurent Vivier                                      env->regs[4],
447d9673512SLaurent Vivier                                      env->regs[5],
448d9673512SLaurent Vivier                                      0, 0);
449af254a27SRichard Henderson                     if (ret == -QEMU_ERESTARTSYS) {
450d9673512SLaurent Vivier                         env->regs[15] -= env->thumb ? 2 : 4;
45157a0c938SRichard Henderson                     } else if (ret != -QEMU_ESIGRETURN) {
452d9673512SLaurent Vivier                         env->regs[0] = ret;
453d9673512SLaurent Vivier                     }
454d9673512SLaurent Vivier                 }
455d9673512SLaurent Vivier             }
456d9673512SLaurent Vivier             break;
457d9673512SLaurent Vivier         case EXCP_SEMIHOST:
458ed3a06b1SRichard Henderson             do_common_semihosting(cs);
4594ff5ef9eSAlex Bennée             env->regs[15] += env->thumb ? 2 : 4;
460d9673512SLaurent Vivier             break;
461d9673512SLaurent Vivier         case EXCP_INTERRUPT:
462d9673512SLaurent Vivier             /* just indicate that signals should be handled asap */
463d9673512SLaurent Vivier             break;
464d9673512SLaurent Vivier         case EXCP_PREFETCH_ABORT:
465d9673512SLaurent Vivier         case EXCP_DATA_ABORT:
46639a099caSRichard Henderson             /* For user-only we don't set TTBCR_EAE, so look at the FSR. */
46739a099caSRichard Henderson             switch (env->exception.fsr & 0x1f) {
46839a099caSRichard Henderson             case 0x1: /* Alignment */
46939a099caSRichard Henderson                 si_signo = TARGET_SIGBUS;
47039a099caSRichard Henderson                 si_code = TARGET_BUS_ADRALN;
47139a099caSRichard Henderson                 break;
47239a099caSRichard Henderson             case 0x3: /* Access flag fault, level 1 */
47339a099caSRichard Henderson             case 0x6: /* Access flag fault, level 2 */
47439a099caSRichard Henderson             case 0x9: /* Domain fault, level 1 */
47539a099caSRichard Henderson             case 0xb: /* Domain fault, level 2 */
4765b602fc4SPeter Maydell             case 0xd: /* Permission fault, level 1 */
4775b602fc4SPeter Maydell             case 0xf: /* Permission fault, level 2 */
47839a099caSRichard Henderson                 si_signo = TARGET_SIGSEGV;
47939a099caSRichard Henderson                 si_code = TARGET_SEGV_ACCERR;
48039a099caSRichard Henderson                 break;
48139a099caSRichard Henderson             case 0x5: /* Translation fault, level 1 */
48239a099caSRichard Henderson             case 0x7: /* Translation fault, level 2 */
48339a099caSRichard Henderson                 si_signo = TARGET_SIGSEGV;
48439a099caSRichard Henderson                 si_code = TARGET_SEGV_MAPERR;
48539a099caSRichard Henderson                 break;
48639a099caSRichard Henderson             default:
48739a099caSRichard Henderson                 g_assert_not_reached();
48839a099caSRichard Henderson             }
48939a099caSRichard Henderson             force_sig_fault(si_signo, si_code, env->exception.vaddress);
490d9673512SLaurent Vivier             break;
491d9673512SLaurent Vivier         case EXCP_DEBUG:
49213a0c21eSPeter Maydell         case EXCP_BKPT:
493d9673512SLaurent Vivier         excp_debug:
4944c90f0baSPeter Maydell             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]);
495d9673512SLaurent Vivier             break;
496d9673512SLaurent Vivier         case EXCP_KERNEL_TRAP:
497d9673512SLaurent Vivier             if (do_kernel_trap(env))
498d9673512SLaurent Vivier               goto error;
499d9673512SLaurent Vivier             break;
500d9673512SLaurent Vivier         case EXCP_YIELD:
501d9673512SLaurent Vivier             /* nothing to do here for user-mode, just resume guest code */
502d9673512SLaurent Vivier             break;
503d9673512SLaurent Vivier         case EXCP_ATOMIC:
504d9673512SLaurent Vivier             cpu_exec_step_atomic(cs);
505d9673512SLaurent Vivier             break;
506d9673512SLaurent Vivier         default:
507d9673512SLaurent Vivier         error:
508d9673512SLaurent Vivier             EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
509d9673512SLaurent Vivier             abort();
510d9673512SLaurent Vivier         }
511d9673512SLaurent Vivier         process_pending_signals(env);
512d9673512SLaurent Vivier     }
513d9673512SLaurent Vivier }
514d9673512SLaurent Vivier 
target_cpu_copy_regs(CPUArchState * env,struct target_pt_regs * regs)515cd71c089SLaurent Vivier void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
516cd71c089SLaurent Vivier {
51729a0af61SRichard Henderson     CPUState *cpu = env_cpu(env);
518e4e5cb4aSIlya Leoshkevich     TaskState *ts = get_task_state(cpu);
519d9673512SLaurent Vivier     struct image_info *info = ts->info;
520d9673512SLaurent Vivier     int i;
521d9673512SLaurent Vivier 
522d9673512SLaurent Vivier     cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
523d9673512SLaurent Vivier                CPSRWriteByInstr);
524d9673512SLaurent Vivier     for(i = 0; i < 16; i++) {
525d9673512SLaurent Vivier         env->regs[i] = regs->uregs[i];
526d9673512SLaurent Vivier     }
527ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN
528d9673512SLaurent Vivier     /* Enable BE8.  */
529d9673512SLaurent Vivier     if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
530d9673512SLaurent Vivier         && (info->elf_flags & EF_ARM_BE8)) {
531d9673512SLaurent Vivier         env->uncached_cpsr |= CPSR_E;
532d9673512SLaurent Vivier         env->cp15.sctlr_el[1] |= SCTLR_E0E;
533d9673512SLaurent Vivier     } else {
534d9673512SLaurent Vivier         env->cp15.sctlr_el[1] |= SCTLR_B;
535d9673512SLaurent Vivier     }
53637bf16c6SRichard Henderson     arm_rebuild_hflags(env);
537d9673512SLaurent Vivier #endif
538d9673512SLaurent Vivier 
539d9673512SLaurent Vivier     ts->stack_base = info->start_stack;
540d9673512SLaurent Vivier     ts->heap_base = info->brk;
541d9673512SLaurent Vivier     /* This will be filled in on the first SYS_HEAPINFO call.  */
542d9673512SLaurent Vivier     ts->heap_limit = 0;
543cd71c089SLaurent Vivier }
544