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