xref: /qemu/linux-user/main.c (revision ba02577c)
131e31b8aSbellard /*
293ac68bcSbellard  *  qemu user main
331e31b8aSbellard  *
468d0f70eSbellard  *  Copyright (c) 2003-2008 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1831e31b8aSbellard  */
1931e31b8aSbellard #include <stdlib.h>
2031e31b8aSbellard #include <stdio.h>
2131e31b8aSbellard #include <stdarg.h>
2204369ff2Sbellard #include <string.h>
2331e31b8aSbellard #include <errno.h>
240ecfa993Sbellard #include <unistd.h>
25e441570fSbalrog #include <sys/mman.h>
26edf8e2afSMika Westerberg #include <sys/syscall.h>
27703e0e89SRichard Henderson #include <sys/resource.h>
2831e31b8aSbellard 
293ef693a0Sbellard #include "qemu.h"
30ca10f867Saurel32 #include "qemu-common.h"
312b41f10eSBlue Swirl #include "cpu.h"
329002ec79SRichard Henderson #include "tcg.h"
331de7afc9SPaolo Bonzini #include "qemu/timer.h"
341de7afc9SPaolo Bonzini #include "qemu/envlist.h"
35d8fd2954SPaul Brook #include "elf.h"
3604a6dfebSaurel32 
37d088d664Saurel32 char *exec_path;
38d088d664Saurel32 
391b530a6dSaurel32 int singlestep;
408cb76755SStefan Weil static const char *filename;
418cb76755SStefan Weil static const char *argv0;
428cb76755SStefan Weil static int gdbstub_port;
438cb76755SStefan Weil static envlist_t *envlist;
4451fb256aSAndreas Färber static const char *cpu_model;
45379f6698SPaul Brook unsigned long mmap_min_addr;
46379f6698SPaul Brook unsigned long guest_base;
47379f6698SPaul Brook int have_guest_base;
48288e65b9SAlexander Graf #if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
49288e65b9SAlexander Graf /*
50288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
51288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
52288e65b9SAlexander Graf  *
53288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
54288e65b9SAlexander Graf  * or anything else that QEMU maps.
55288e65b9SAlexander Graf  */
56314992b1SAlexander Graf # ifdef TARGET_MIPS
57314992b1SAlexander Graf /* MIPS only supports 31 bits of virtual address space for user space */
58314992b1SAlexander Graf unsigned long reserved_va = 0x77000000;
59314992b1SAlexander Graf # else
60288e65b9SAlexander Graf unsigned long reserved_va = 0xf7000000;
61314992b1SAlexander Graf # endif
62288e65b9SAlexander Graf #else
6368a1c816SPaul Brook unsigned long reserved_va;
64379f6698SPaul Brook #endif
651b530a6dSaurel32 
66d03f9c32SMeador Inge static void usage(int exitcode);
67fc9c5412SJohannes Schauer 
687ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
69e586822aSRiku Voipio const char *qemu_uname_release;
70586314f2Sbellard 
719de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
729de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
739de5e440Sbellard    by remapping the process stack directly at the right place */
74703e0e89SRichard Henderson unsigned long guest_stack_size = 8 * 1024 * 1024UL;
7531e31b8aSbellard 
7631e31b8aSbellard void gemu_log(const char *fmt, ...)
7731e31b8aSbellard {
7831e31b8aSbellard     va_list ap;
7931e31b8aSbellard 
8031e31b8aSbellard     va_start(ap, fmt);
8131e31b8aSbellard     vfprintf(stderr, fmt, ap);
8231e31b8aSbellard     va_end(ap);
8331e31b8aSbellard }
8431e31b8aSbellard 
858fcd3692Sblueswir1 #if defined(TARGET_I386)
8605390248SAndreas Färber int cpu_get_pic_interrupt(CPUX86State *env)
8792ccca6aSbellard {
8892ccca6aSbellard     return -1;
8992ccca6aSbellard }
908fcd3692Sblueswir1 #endif
9192ccca6aSbellard 
92d5975363Spbrook /***********************************************************/
93d5975363Spbrook /* Helper routines for implementing atomic operations.  */
94d5975363Spbrook 
95d5975363Spbrook /* To implement exclusive operations we force all cpus to syncronise.
96d5975363Spbrook    We don't require a full sync, only that no cpus are executing guest code.
97d5975363Spbrook    The alternative is to map target atomic ops onto host equivalents,
98d5975363Spbrook    which requires quite a lot of per host/target work.  */
99c2764719Spbrook static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
100d5975363Spbrook static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
101d5975363Spbrook static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
102d5975363Spbrook static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
103d5975363Spbrook static int pending_cpus;
104d5975363Spbrook 
105d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
106d5975363Spbrook void fork_start(void)
107d5975363Spbrook {
108677ef623SKONRAD Frederic     qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
109d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
110d032d1b4SRiku Voipio     mmap_fork_start();
111d5975363Spbrook }
112d5975363Spbrook 
113d5975363Spbrook void fork_end(int child)
114d5975363Spbrook {
115d032d1b4SRiku Voipio     mmap_fork_end(child);
116d5975363Spbrook     if (child) {
117bdc44640SAndreas Färber         CPUState *cpu, *next_cpu;
118d5975363Spbrook         /* Child processes created by fork() only have a single thread.
119d5975363Spbrook            Discard information about the parent threads.  */
120bdc44640SAndreas Färber         CPU_FOREACH_SAFE(cpu, next_cpu) {
121bdc44640SAndreas Färber             if (cpu != thread_cpu) {
122bdc44640SAndreas Färber                 QTAILQ_REMOVE(&cpus, thread_cpu, node);
123bdc44640SAndreas Färber             }
124bdc44640SAndreas Färber         }
125d5975363Spbrook         pending_cpus = 0;
126d5975363Spbrook         pthread_mutex_init(&exclusive_lock, NULL);
127c2764719Spbrook         pthread_mutex_init(&cpu_list_mutex, NULL);
128d5975363Spbrook         pthread_cond_init(&exclusive_cond, NULL);
129d5975363Spbrook         pthread_cond_init(&exclusive_resume, NULL);
130677ef623SKONRAD Frederic         qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock);
131f7ec7f7bSPeter Crosthwaite         gdbserver_fork(thread_cpu);
132d5975363Spbrook     } else {
133d5975363Spbrook         pthread_mutex_unlock(&exclusive_lock);
134677ef623SKONRAD Frederic         qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
135d5975363Spbrook     }
136d5975363Spbrook }
137d5975363Spbrook 
138d5975363Spbrook /* Wait for pending exclusive operations to complete.  The exclusive lock
139d5975363Spbrook    must be held.  */
140d5975363Spbrook static inline void exclusive_idle(void)
141d5975363Spbrook {
142d5975363Spbrook     while (pending_cpus) {
143d5975363Spbrook         pthread_cond_wait(&exclusive_resume, &exclusive_lock);
144d5975363Spbrook     }
145d5975363Spbrook }
146d5975363Spbrook 
147d5975363Spbrook /* Start an exclusive operation.
148d5975363Spbrook    Must only be called from outside cpu_arm_exec.   */
149d5975363Spbrook static inline void start_exclusive(void)
150d5975363Spbrook {
1510315c31cSAndreas Färber     CPUState *other_cpu;
1520315c31cSAndreas Färber 
153d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
154d5975363Spbrook     exclusive_idle();
155d5975363Spbrook 
156d5975363Spbrook     pending_cpus = 1;
157d5975363Spbrook     /* Make all other cpus stop executing.  */
158bdc44640SAndreas Färber     CPU_FOREACH(other_cpu) {
1590315c31cSAndreas Färber         if (other_cpu->running) {
160d5975363Spbrook             pending_cpus++;
16160a3e17aSAndreas Färber             cpu_exit(other_cpu);
162d5975363Spbrook         }
163d5975363Spbrook     }
164d5975363Spbrook     if (pending_cpus > 1) {
165d5975363Spbrook         pthread_cond_wait(&exclusive_cond, &exclusive_lock);
166d5975363Spbrook     }
167d5975363Spbrook }
168d5975363Spbrook 
169d5975363Spbrook /* Finish an exclusive operation.  */
170f7e61b22SPeter Maydell static inline void __attribute__((unused)) end_exclusive(void)
171d5975363Spbrook {
172d5975363Spbrook     pending_cpus = 0;
173d5975363Spbrook     pthread_cond_broadcast(&exclusive_resume);
174d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
175d5975363Spbrook }
176d5975363Spbrook 
177d5975363Spbrook /* Wait for exclusive ops to finish, and begin cpu execution.  */
1780315c31cSAndreas Färber static inline void cpu_exec_start(CPUState *cpu)
179d5975363Spbrook {
180d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
181d5975363Spbrook     exclusive_idle();
1820315c31cSAndreas Färber     cpu->running = true;
183d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
184d5975363Spbrook }
185d5975363Spbrook 
186d5975363Spbrook /* Mark cpu as not executing, and release pending exclusive ops.  */
1870315c31cSAndreas Färber static inline void cpu_exec_end(CPUState *cpu)
188d5975363Spbrook {
189d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
1900315c31cSAndreas Färber     cpu->running = false;
191d5975363Spbrook     if (pending_cpus > 1) {
192d5975363Spbrook         pending_cpus--;
193d5975363Spbrook         if (pending_cpus == 1) {
194d5975363Spbrook             pthread_cond_signal(&exclusive_cond);
195d5975363Spbrook         }
196d5975363Spbrook     }
197d5975363Spbrook     exclusive_idle();
198d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
199d5975363Spbrook }
200c2764719Spbrook 
201c2764719Spbrook void cpu_list_lock(void)
202c2764719Spbrook {
203c2764719Spbrook     pthread_mutex_lock(&cpu_list_mutex);
204c2764719Spbrook }
205c2764719Spbrook 
206c2764719Spbrook void cpu_list_unlock(void)
207c2764719Spbrook {
208c2764719Spbrook     pthread_mutex_unlock(&cpu_list_mutex);
209c2764719Spbrook }
210d5975363Spbrook 
211d5975363Spbrook 
212a541f297Sbellard #ifdef TARGET_I386
213a541f297Sbellard /***********************************************************/
214a541f297Sbellard /* CPUX86 core interface */
215a541f297Sbellard 
21628ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env)
21728ab0e2eSbellard {
21828ab0e2eSbellard     return cpu_get_real_ticks();
21928ab0e2eSbellard }
22028ab0e2eSbellard 
221f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
222f4beb510Sbellard                      int flags)
2236dbad63eSbellard {
224f4beb510Sbellard     unsigned int e1, e2;
22553a5960aSpbrook     uint32_t *p;
2266dbad63eSbellard     e1 = (addr << 16) | (limit & 0xffff);
2276dbad63eSbellard     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
228f4beb510Sbellard     e2 |= flags;
22953a5960aSpbrook     p = ptr;
230d538e8f5Smalc     p[0] = tswap32(e1);
231d538e8f5Smalc     p[1] = tswap32(e2);
232f4beb510Sbellard }
233f4beb510Sbellard 
234e441570fSbalrog static uint64_t *idt_table;
235eb38c52cSblueswir1 #ifdef TARGET_X86_64
236d2fd1af7Sbellard static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
237d2fd1af7Sbellard                        uint64_t addr, unsigned int sel)
238d2fd1af7Sbellard {
2394dbc422bSbellard     uint32_t *p, e1, e2;
240d2fd1af7Sbellard     e1 = (addr & 0xffff) | (sel << 16);
241d2fd1af7Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
242d2fd1af7Sbellard     p = ptr;
2434dbc422bSbellard     p[0] = tswap32(e1);
2444dbc422bSbellard     p[1] = tswap32(e2);
2454dbc422bSbellard     p[2] = tswap32(addr >> 32);
2464dbc422bSbellard     p[3] = 0;
247d2fd1af7Sbellard }
248d2fd1af7Sbellard /* only dpl matters as we do only user space emulation */
249d2fd1af7Sbellard static void set_idt(int n, unsigned int dpl)
250d2fd1af7Sbellard {
251d2fd1af7Sbellard     set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
252d2fd1af7Sbellard }
253d2fd1af7Sbellard #else
254f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
255d2fd1af7Sbellard                      uint32_t addr, unsigned int sel)
256f4beb510Sbellard {
2574dbc422bSbellard     uint32_t *p, e1, e2;
258f4beb510Sbellard     e1 = (addr & 0xffff) | (sel << 16);
259f4beb510Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
26053a5960aSpbrook     p = ptr;
2614dbc422bSbellard     p[0] = tswap32(e1);
2624dbc422bSbellard     p[1] = tswap32(e2);
2636dbad63eSbellard }
2646dbad63eSbellard 
265f4beb510Sbellard /* only dpl matters as we do only user space emulation */
266f4beb510Sbellard static void set_idt(int n, unsigned int dpl)
267f4beb510Sbellard {
268f4beb510Sbellard     set_gate(idt_table + n, 0, dpl, 0, 0);
269f4beb510Sbellard }
270d2fd1af7Sbellard #endif
27131e31b8aSbellard 
27289e957e7Sbellard void cpu_loop(CPUX86State *env)
273bc8a22ccSbellard {
274db6b81d4SAndreas Färber     CPUState *cs = CPU(x86_env_get_cpu(env));
275bc8a22ccSbellard     int trapnr;
276992f48a0Sblueswir1     abi_ulong pc;
277c227f099SAnthony Liguori     target_siginfo_t info;
278bc8a22ccSbellard 
279bc8a22ccSbellard     for(;;) {
280b040bc9cSPeter Maydell         cpu_exec_start(cs);
281ea3e9847SPeter Crosthwaite         trapnr = cpu_x86_exec(cs);
282b040bc9cSPeter Maydell         cpu_exec_end(cs);
283bc8a22ccSbellard         switch(trapnr) {
284f4beb510Sbellard         case 0x80:
285d2fd1af7Sbellard             /* linux syscall from int $0x80 */
2861b6b029eSbellard             env->regs[R_EAX] = do_syscall(env,
2871b6b029eSbellard                                           env->regs[R_EAX],
2881b6b029eSbellard                                           env->regs[R_EBX],
2891b6b029eSbellard                                           env->regs[R_ECX],
2901b6b029eSbellard                                           env->regs[R_EDX],
2911b6b029eSbellard                                           env->regs[R_ESI],
2921b6b029eSbellard                                           env->regs[R_EDI],
2935945cfcbSPeter Maydell                                           env->regs[R_EBP],
2945945cfcbSPeter Maydell                                           0, 0);
295f4beb510Sbellard             break;
296d2fd1af7Sbellard #ifndef TARGET_ABI32
297d2fd1af7Sbellard         case EXCP_SYSCALL:
2985ba18547SStefan Weil             /* linux syscall from syscall instruction */
299d2fd1af7Sbellard             env->regs[R_EAX] = do_syscall(env,
300d2fd1af7Sbellard                                           env->regs[R_EAX],
301d2fd1af7Sbellard                                           env->regs[R_EDI],
302d2fd1af7Sbellard                                           env->regs[R_ESI],
303d2fd1af7Sbellard                                           env->regs[R_EDX],
304d2fd1af7Sbellard                                           env->regs[10],
305d2fd1af7Sbellard                                           env->regs[8],
3065945cfcbSPeter Maydell                                           env->regs[9],
3075945cfcbSPeter Maydell                                           0, 0);
308d2fd1af7Sbellard             break;
309d2fd1af7Sbellard #endif
310f4beb510Sbellard         case EXCP0B_NOSEG:
311f4beb510Sbellard         case EXCP0C_STACK:
312a86b3c64SChen Gang S             info.si_signo = TARGET_SIGBUS;
313f4beb510Sbellard             info.si_errno = 0;
314f4beb510Sbellard             info.si_code = TARGET_SI_KERNEL;
315f4beb510Sbellard             info._sifields._sigfault._addr = 0;
316624f7979Spbrook             queue_signal(env, info.si_signo, &info);
317f4beb510Sbellard             break;
318f4beb510Sbellard         case EXCP0D_GPF:
319d2fd1af7Sbellard             /* XXX: potential problem if ABI32 */
32084409ddbSj_mayer #ifndef TARGET_X86_64
321f4beb510Sbellard             if (env->eflags & VM_MASK) {
322f4beb510Sbellard                 handle_vm86_fault(env);
32384409ddbSj_mayer             } else
32484409ddbSj_mayer #endif
32584409ddbSj_mayer             {
326a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGSEGV;
3279de5e440Sbellard                 info.si_errno = 0;
328b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
3299de5e440Sbellard                 info._sifields._sigfault._addr = 0;
330624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
3311b6b029eSbellard             }
3321b6b029eSbellard             break;
333b689bc57Sbellard         case EXCP0E_PAGE:
334a86b3c64SChen Gang S             info.si_signo = TARGET_SIGSEGV;
335b689bc57Sbellard             info.si_errno = 0;
336b689bc57Sbellard             if (!(env->error_code & 1))
337b689bc57Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
338b689bc57Sbellard             else
339b689bc57Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
340970a87a6Sbellard             info._sifields._sigfault._addr = env->cr[2];
341624f7979Spbrook             queue_signal(env, info.si_signo, &info);
342b689bc57Sbellard             break;
3439de5e440Sbellard         case EXCP00_DIVZ:
34484409ddbSj_mayer #ifndef TARGET_X86_64
345bc8a22ccSbellard             if (env->eflags & VM_MASK) {
346447db213Sbellard                 handle_vm86_trap(env, trapnr);
34784409ddbSj_mayer             } else
34884409ddbSj_mayer #endif
34984409ddbSj_mayer             {
3509de5e440Sbellard                 /* division by zero */
351a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGFPE;
3529de5e440Sbellard                 info.si_errno = 0;
3539de5e440Sbellard                 info.si_code = TARGET_FPE_INTDIV;
3549de5e440Sbellard                 info._sifields._sigfault._addr = env->eip;
355624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
356bc8a22ccSbellard             }
3579de5e440Sbellard             break;
35801df040bSaliguori         case EXCP01_DB:
359447db213Sbellard         case EXCP03_INT3:
36084409ddbSj_mayer #ifndef TARGET_X86_64
361447db213Sbellard             if (env->eflags & VM_MASK) {
362447db213Sbellard                 handle_vm86_trap(env, trapnr);
36384409ddbSj_mayer             } else
36484409ddbSj_mayer #endif
36584409ddbSj_mayer             {
366a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGTRAP;
367447db213Sbellard                 info.si_errno = 0;
36801df040bSaliguori                 if (trapnr == EXCP01_DB) {
369447db213Sbellard                     info.si_code = TARGET_TRAP_BRKPT;
370447db213Sbellard                     info._sifields._sigfault._addr = env->eip;
371447db213Sbellard                 } else {
372447db213Sbellard                     info.si_code = TARGET_SI_KERNEL;
373447db213Sbellard                     info._sifields._sigfault._addr = 0;
374447db213Sbellard                 }
375624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
376447db213Sbellard             }
377447db213Sbellard             break;
3789de5e440Sbellard         case EXCP04_INTO:
3799de5e440Sbellard         case EXCP05_BOUND:
38084409ddbSj_mayer #ifndef TARGET_X86_64
381bc8a22ccSbellard             if (env->eflags & VM_MASK) {
382447db213Sbellard                 handle_vm86_trap(env, trapnr);
38384409ddbSj_mayer             } else
38484409ddbSj_mayer #endif
38584409ddbSj_mayer             {
386a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGSEGV;
3879de5e440Sbellard                 info.si_errno = 0;
388b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
3899de5e440Sbellard                 info._sifields._sigfault._addr = 0;
390624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
391bc8a22ccSbellard             }
3929de5e440Sbellard             break;
3939de5e440Sbellard         case EXCP06_ILLOP:
394a86b3c64SChen Gang S             info.si_signo = TARGET_SIGILL;
3959de5e440Sbellard             info.si_errno = 0;
3969de5e440Sbellard             info.si_code = TARGET_ILL_ILLOPN;
3979de5e440Sbellard             info._sifields._sigfault._addr = env->eip;
398624f7979Spbrook             queue_signal(env, info.si_signo, &info);
3999de5e440Sbellard             break;
4009de5e440Sbellard         case EXCP_INTERRUPT:
4019de5e440Sbellard             /* just indicate that signals should be handled asap */
4029de5e440Sbellard             break;
4031fddef4bSbellard         case EXCP_DEBUG:
4041fddef4bSbellard             {
4051fddef4bSbellard                 int sig;
4061fddef4bSbellard 
407db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
4081fddef4bSbellard                 if (sig)
4091fddef4bSbellard                   {
4101fddef4bSbellard                     info.si_signo = sig;
4111fddef4bSbellard                     info.si_errno = 0;
4121fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
413624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
4141fddef4bSbellard                   }
4151fddef4bSbellard             }
4161fddef4bSbellard             break;
4171b6b029eSbellard         default:
418970a87a6Sbellard             pc = env->segs[R_CS].base + env->eip;
419bc8a22ccSbellard             fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
420bc8a22ccSbellard                     (long)pc, trapnr);
4211b6b029eSbellard             abort();
4221b6b029eSbellard         }
42366fb9763Sbellard         process_pending_signals(env);
4241b6b029eSbellard     }
4251b6b029eSbellard }
426b346ff46Sbellard #endif
427b346ff46Sbellard 
428b346ff46Sbellard #ifdef TARGET_ARM
429b346ff46Sbellard 
430d8fd2954SPaul Brook #define get_user_code_u32(x, gaddr, doswap)             \
431d8fd2954SPaul Brook     ({ abi_long __r = get_user_u32((x), (gaddr));       \
432d8fd2954SPaul Brook         if (!__r && (doswap)) {                         \
433d8fd2954SPaul Brook             (x) = bswap32(x);                           \
434d8fd2954SPaul Brook         }                                               \
435d8fd2954SPaul Brook         __r;                                            \
436d8fd2954SPaul Brook     })
437d8fd2954SPaul Brook 
438d8fd2954SPaul Brook #define get_user_code_u16(x, gaddr, doswap)             \
439d8fd2954SPaul Brook     ({ abi_long __r = get_user_u16((x), (gaddr));       \
440d8fd2954SPaul Brook         if (!__r && (doswap)) {                         \
441d8fd2954SPaul Brook             (x) = bswap16(x);                           \
442d8fd2954SPaul Brook         }                                               \
443d8fd2954SPaul Brook         __r;                                            \
444d8fd2954SPaul Brook     })
445d8fd2954SPaul Brook 
4461861c454SPeter Maydell #ifdef TARGET_ABI32
4471861c454SPeter Maydell /* Commpage handling -- there is no commpage for AArch64 */
4481861c454SPeter Maydell 
44997cc7560SDr. David Alan Gilbert /*
45097cc7560SDr. David Alan Gilbert  * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
45197cc7560SDr. David Alan Gilbert  * Input:
45297cc7560SDr. David Alan Gilbert  * r0 = pointer to oldval
45397cc7560SDr. David Alan Gilbert  * r1 = pointer to newval
45497cc7560SDr. David Alan Gilbert  * r2 = pointer to target value
45597cc7560SDr. David Alan Gilbert  *
45697cc7560SDr. David Alan Gilbert  * Output:
45797cc7560SDr. David Alan Gilbert  * r0 = 0 if *ptr was changed, non-0 if no exchange happened
45897cc7560SDr. David Alan Gilbert  * C set if *ptr was changed, clear if no exchange happened
45997cc7560SDr. David Alan Gilbert  *
46097cc7560SDr. David Alan Gilbert  * Note segv's in kernel helpers are a bit tricky, we can set the
46197cc7560SDr. David Alan Gilbert  * data address sensibly but the PC address is just the entry point.
46297cc7560SDr. David Alan Gilbert  */
46397cc7560SDr. David Alan Gilbert static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
46497cc7560SDr. David Alan Gilbert {
46597cc7560SDr. David Alan Gilbert     uint64_t oldval, newval, val;
46697cc7560SDr. David Alan Gilbert     uint32_t addr, cpsr;
46797cc7560SDr. David Alan Gilbert     target_siginfo_t info;
46897cc7560SDr. David Alan Gilbert 
46997cc7560SDr. David Alan Gilbert     /* Based on the 32 bit code in do_kernel_trap */
47097cc7560SDr. David Alan Gilbert 
47197cc7560SDr. David Alan Gilbert     /* XXX: This only works between threads, not between processes.
47297cc7560SDr. David Alan Gilbert        It's probably possible to implement this with native host
47397cc7560SDr. David Alan Gilbert        operations. However things like ldrex/strex are much harder so
47497cc7560SDr. David Alan Gilbert        there's not much point trying.  */
47597cc7560SDr. David Alan Gilbert     start_exclusive();
47697cc7560SDr. David Alan Gilbert     cpsr = cpsr_read(env);
47797cc7560SDr. David Alan Gilbert     addr = env->regs[2];
47897cc7560SDr. David Alan Gilbert 
47997cc7560SDr. David Alan Gilbert     if (get_user_u64(oldval, env->regs[0])) {
480abf1172fSPeter Maydell         env->exception.vaddress = env->regs[0];
48197cc7560SDr. David Alan Gilbert         goto segv;
48297cc7560SDr. David Alan Gilbert     };
48397cc7560SDr. David Alan Gilbert 
48497cc7560SDr. David Alan Gilbert     if (get_user_u64(newval, env->regs[1])) {
485abf1172fSPeter Maydell         env->exception.vaddress = env->regs[1];
48697cc7560SDr. David Alan Gilbert         goto segv;
48797cc7560SDr. David Alan Gilbert     };
48897cc7560SDr. David Alan Gilbert 
48997cc7560SDr. David Alan Gilbert     if (get_user_u64(val, addr)) {
490abf1172fSPeter Maydell         env->exception.vaddress = addr;
49197cc7560SDr. David Alan Gilbert         goto segv;
49297cc7560SDr. David Alan Gilbert     }
49397cc7560SDr. David Alan Gilbert 
49497cc7560SDr. David Alan Gilbert     if (val == oldval) {
49597cc7560SDr. David Alan Gilbert         val = newval;
49697cc7560SDr. David Alan Gilbert 
49797cc7560SDr. David Alan Gilbert         if (put_user_u64(val, addr)) {
498abf1172fSPeter Maydell             env->exception.vaddress = addr;
49997cc7560SDr. David Alan Gilbert             goto segv;
50097cc7560SDr. David Alan Gilbert         };
50197cc7560SDr. David Alan Gilbert 
50297cc7560SDr. David Alan Gilbert         env->regs[0] = 0;
50397cc7560SDr. David Alan Gilbert         cpsr |= CPSR_C;
50497cc7560SDr. David Alan Gilbert     } else {
50597cc7560SDr. David Alan Gilbert         env->regs[0] = -1;
50697cc7560SDr. David Alan Gilbert         cpsr &= ~CPSR_C;
50797cc7560SDr. David Alan Gilbert     }
50897cc7560SDr. David Alan Gilbert     cpsr_write(env, cpsr, CPSR_C);
50997cc7560SDr. David Alan Gilbert     end_exclusive();
51097cc7560SDr. David Alan Gilbert     return;
51197cc7560SDr. David Alan Gilbert 
51297cc7560SDr. David Alan Gilbert segv:
51397cc7560SDr. David Alan Gilbert     end_exclusive();
51497cc7560SDr. David Alan Gilbert     /* We get the PC of the entry address - which is as good as anything,
51597cc7560SDr. David Alan Gilbert        on a real kernel what you get depends on which mode it uses. */
516a86b3c64SChen Gang S     info.si_signo = TARGET_SIGSEGV;
51797cc7560SDr. David Alan Gilbert     info.si_errno = 0;
51897cc7560SDr. David Alan Gilbert     /* XXX: check env->error_code */
51997cc7560SDr. David Alan Gilbert     info.si_code = TARGET_SEGV_MAPERR;
520abf1172fSPeter Maydell     info._sifields._sigfault._addr = env->exception.vaddress;
52197cc7560SDr. David Alan Gilbert     queue_signal(env, info.si_signo, &info);
52297cc7560SDr. David Alan Gilbert }
52397cc7560SDr. David Alan Gilbert 
524fbb4a2e3Spbrook /* Handle a jump to the kernel code page.  */
525fbb4a2e3Spbrook static int
526fbb4a2e3Spbrook do_kernel_trap(CPUARMState *env)
527fbb4a2e3Spbrook {
528fbb4a2e3Spbrook     uint32_t addr;
529fbb4a2e3Spbrook     uint32_t cpsr;
530fbb4a2e3Spbrook     uint32_t val;
531fbb4a2e3Spbrook 
532fbb4a2e3Spbrook     switch (env->regs[15]) {
533fbb4a2e3Spbrook     case 0xffff0fa0: /* __kernel_memory_barrier */
534fbb4a2e3Spbrook         /* ??? No-op. Will need to do better for SMP.  */
535fbb4a2e3Spbrook         break;
536fbb4a2e3Spbrook     case 0xffff0fc0: /* __kernel_cmpxchg */
537d5975363Spbrook          /* XXX: This only works between threads, not between processes.
538d5975363Spbrook             It's probably possible to implement this with native host
539d5975363Spbrook             operations. However things like ldrex/strex are much harder so
540d5975363Spbrook             there's not much point trying.  */
541d5975363Spbrook         start_exclusive();
542fbb4a2e3Spbrook         cpsr = cpsr_read(env);
543fbb4a2e3Spbrook         addr = env->regs[2];
544fbb4a2e3Spbrook         /* FIXME: This should SEGV if the access fails.  */
545fbb4a2e3Spbrook         if (get_user_u32(val, addr))
546fbb4a2e3Spbrook             val = ~env->regs[0];
547fbb4a2e3Spbrook         if (val == env->regs[0]) {
548fbb4a2e3Spbrook             val = env->regs[1];
549fbb4a2e3Spbrook             /* FIXME: Check for segfaults.  */
550fbb4a2e3Spbrook             put_user_u32(val, addr);
551fbb4a2e3Spbrook             env->regs[0] = 0;
552fbb4a2e3Spbrook             cpsr |= CPSR_C;
553fbb4a2e3Spbrook         } else {
554fbb4a2e3Spbrook             env->regs[0] = -1;
555fbb4a2e3Spbrook             cpsr &= ~CPSR_C;
556fbb4a2e3Spbrook         }
557fbb4a2e3Spbrook         cpsr_write(env, cpsr, CPSR_C);
558d5975363Spbrook         end_exclusive();
559fbb4a2e3Spbrook         break;
560fbb4a2e3Spbrook     case 0xffff0fe0: /* __kernel_get_tls */
561b8d43285SMikhail Ilyin         env->regs[0] = cpu_get_tls(env);
562fbb4a2e3Spbrook         break;
56397cc7560SDr. David Alan Gilbert     case 0xffff0f60: /* __kernel_cmpxchg64 */
56497cc7560SDr. David Alan Gilbert         arm_kernel_cmpxchg64_helper(env);
56597cc7560SDr. David Alan Gilbert         break;
56697cc7560SDr. David Alan Gilbert 
567fbb4a2e3Spbrook     default:
568fbb4a2e3Spbrook         return 1;
569fbb4a2e3Spbrook     }
570fbb4a2e3Spbrook     /* Jump back to the caller.  */
571fbb4a2e3Spbrook     addr = env->regs[14];
572fbb4a2e3Spbrook     if (addr & 1) {
573fbb4a2e3Spbrook         env->thumb = 1;
574fbb4a2e3Spbrook         addr &= ~1;
575fbb4a2e3Spbrook     }
576fbb4a2e3Spbrook     env->regs[15] = addr;
577fbb4a2e3Spbrook 
578fbb4a2e3Spbrook     return 0;
579fbb4a2e3Spbrook }
580fbb4a2e3Spbrook 
581fa2ef212SMichael Matz /* Store exclusive handling for AArch32 */
582426f5abcSPaul Brook static int do_strex(CPUARMState *env)
583426f5abcSPaul Brook {
58403d05e2dSPeter Maydell     uint64_t val;
585426f5abcSPaul Brook     int size;
586426f5abcSPaul Brook     int rc = 1;
587426f5abcSPaul Brook     int segv = 0;
588426f5abcSPaul Brook     uint32_t addr;
589426f5abcSPaul Brook     start_exclusive();
59003d05e2dSPeter Maydell     if (env->exclusive_addr != env->exclusive_test) {
591426f5abcSPaul Brook         goto fail;
592426f5abcSPaul Brook     }
59303d05e2dSPeter Maydell     /* We know we're always AArch32 so the address is in uint32_t range
59403d05e2dSPeter Maydell      * unless it was the -1 exclusive-monitor-lost value (which won't
59503d05e2dSPeter Maydell      * match exclusive_test above).
59603d05e2dSPeter Maydell      */
59703d05e2dSPeter Maydell     assert(extract64(env->exclusive_addr, 32, 32) == 0);
59803d05e2dSPeter Maydell     addr = env->exclusive_addr;
599426f5abcSPaul Brook     size = env->exclusive_info & 0xf;
600426f5abcSPaul Brook     switch (size) {
601426f5abcSPaul Brook     case 0:
602426f5abcSPaul Brook         segv = get_user_u8(val, addr);
603426f5abcSPaul Brook         break;
604426f5abcSPaul Brook     case 1:
605426f5abcSPaul Brook         segv = get_user_u16(val, addr);
606426f5abcSPaul Brook         break;
607426f5abcSPaul Brook     case 2:
608426f5abcSPaul Brook     case 3:
609426f5abcSPaul Brook         segv = get_user_u32(val, addr);
610426f5abcSPaul Brook         break;
611f7001a3bSAurelien Jarno     default:
612f7001a3bSAurelien Jarno         abort();
613426f5abcSPaul Brook     }
614426f5abcSPaul Brook     if (segv) {
615abf1172fSPeter Maydell         env->exception.vaddress = addr;
616426f5abcSPaul Brook         goto done;
617426f5abcSPaul Brook     }
618426f5abcSPaul Brook     if (size == 3) {
61903d05e2dSPeter Maydell         uint32_t valhi;
62003d05e2dSPeter Maydell         segv = get_user_u32(valhi, addr + 4);
621426f5abcSPaul Brook         if (segv) {
622abf1172fSPeter Maydell             env->exception.vaddress = addr + 4;
623426f5abcSPaul Brook             goto done;
624426f5abcSPaul Brook         }
62503d05e2dSPeter Maydell         val = deposit64(val, 32, 32, valhi);
62603d05e2dSPeter Maydell     }
62703d05e2dSPeter Maydell     if (val != env->exclusive_val) {
628426f5abcSPaul Brook         goto fail;
629426f5abcSPaul Brook     }
63003d05e2dSPeter Maydell 
631426f5abcSPaul Brook     val = env->regs[(env->exclusive_info >> 8) & 0xf];
632426f5abcSPaul Brook     switch (size) {
633426f5abcSPaul Brook     case 0:
634426f5abcSPaul Brook         segv = put_user_u8(val, addr);
635426f5abcSPaul Brook         break;
636426f5abcSPaul Brook     case 1:
637426f5abcSPaul Brook         segv = put_user_u16(val, addr);
638426f5abcSPaul Brook         break;
639426f5abcSPaul Brook     case 2:
640426f5abcSPaul Brook     case 3:
641426f5abcSPaul Brook         segv = put_user_u32(val, addr);
642426f5abcSPaul Brook         break;
643426f5abcSPaul Brook     }
644426f5abcSPaul Brook     if (segv) {
645abf1172fSPeter Maydell         env->exception.vaddress = addr;
646426f5abcSPaul Brook         goto done;
647426f5abcSPaul Brook     }
648426f5abcSPaul Brook     if (size == 3) {
649426f5abcSPaul Brook         val = env->regs[(env->exclusive_info >> 12) & 0xf];
6502c9adbdaSPeter Maydell         segv = put_user_u32(val, addr + 4);
651426f5abcSPaul Brook         if (segv) {
652abf1172fSPeter Maydell             env->exception.vaddress = addr + 4;
653426f5abcSPaul Brook             goto done;
654426f5abcSPaul Brook         }
655426f5abcSPaul Brook     }
656426f5abcSPaul Brook     rc = 0;
657426f5abcSPaul Brook fail:
658725b8a69SPaul Brook     env->regs[15] += 4;
659426f5abcSPaul Brook     env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
660426f5abcSPaul Brook done:
661426f5abcSPaul Brook     end_exclusive();
662426f5abcSPaul Brook     return segv;
663426f5abcSPaul Brook }
664426f5abcSPaul Brook 
665b346ff46Sbellard void cpu_loop(CPUARMState *env)
666b346ff46Sbellard {
6670315c31cSAndreas Färber     CPUState *cs = CPU(arm_env_get_cpu(env));
668b346ff46Sbellard     int trapnr;
669b346ff46Sbellard     unsigned int n, insn;
670c227f099SAnthony Liguori     target_siginfo_t info;
671b5ff1b31Sbellard     uint32_t addr;
672b346ff46Sbellard 
673b346ff46Sbellard     for(;;) {
6740315c31cSAndreas Färber         cpu_exec_start(cs);
675ea3e9847SPeter Crosthwaite         trapnr = cpu_arm_exec(cs);
6760315c31cSAndreas Färber         cpu_exec_end(cs);
677b346ff46Sbellard         switch(trapnr) {
678b346ff46Sbellard         case EXCP_UDEF:
679c6981055Sbellard             {
6800429a971SAndreas Färber                 TaskState *ts = cs->opaque;
681c6981055Sbellard                 uint32_t opcode;
6826d9a42beSaurel32                 int rc;
683c6981055Sbellard 
684c6981055Sbellard                 /* we handle the FPU emulation here, as Linux */
685c6981055Sbellard                 /* we get the opcode */
6862f619698Sbellard                 /* FIXME - what to do if get_user() fails? */
687d8fd2954SPaul Brook                 get_user_code_u32(opcode, env->regs[15], env->bswap_code);
688c6981055Sbellard 
6896d9a42beSaurel32                 rc = EmulateAll(opcode, &ts->fpa, env);
6906d9a42beSaurel32                 if (rc == 0) { /* illegal instruction */
691a86b3c64SChen Gang S                     info.si_signo = TARGET_SIGILL;
692b346ff46Sbellard                     info.si_errno = 0;
693b346ff46Sbellard                     info.si_code = TARGET_ILL_ILLOPN;
694b346ff46Sbellard                     info._sifields._sigfault._addr = env->regs[15];
695624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
6966d9a42beSaurel32                 } else if (rc < 0) { /* FP exception */
6976d9a42beSaurel32                     int arm_fpe=0;
6986d9a42beSaurel32 
6996d9a42beSaurel32                     /* translate softfloat flags to FPSR flags */
7006d9a42beSaurel32                     if (-rc & float_flag_invalid)
7016d9a42beSaurel32                       arm_fpe |= BIT_IOC;
7026d9a42beSaurel32                     if (-rc & float_flag_divbyzero)
7036d9a42beSaurel32                       arm_fpe |= BIT_DZC;
7046d9a42beSaurel32                     if (-rc & float_flag_overflow)
7056d9a42beSaurel32                       arm_fpe |= BIT_OFC;
7066d9a42beSaurel32                     if (-rc & float_flag_underflow)
7076d9a42beSaurel32                       arm_fpe |= BIT_UFC;
7086d9a42beSaurel32                     if (-rc & float_flag_inexact)
7096d9a42beSaurel32                       arm_fpe |= BIT_IXC;
7106d9a42beSaurel32 
7116d9a42beSaurel32                     FPSR fpsr = ts->fpa.fpsr;
7126d9a42beSaurel32                     //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
7136d9a42beSaurel32 
7146d9a42beSaurel32                     if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
715a86b3c64SChen Gang S                       info.si_signo = TARGET_SIGFPE;
7166d9a42beSaurel32                       info.si_errno = 0;
7176d9a42beSaurel32 
7186d9a42beSaurel32                       /* ordered by priority, least first */
7196d9a42beSaurel32                       if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
7206d9a42beSaurel32                       if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
7216d9a42beSaurel32                       if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
7226d9a42beSaurel32                       if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
7236d9a42beSaurel32                       if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
7246d9a42beSaurel32 
7256d9a42beSaurel32                       info._sifields._sigfault._addr = env->regs[15];
726624f7979Spbrook                       queue_signal(env, info.si_signo, &info);
727c6981055Sbellard                     } else {
7286d9a42beSaurel32                       env->regs[15] += 4;
7296d9a42beSaurel32                     }
7306d9a42beSaurel32 
7316d9a42beSaurel32                     /* accumulate unenabled exceptions */
7326d9a42beSaurel32                     if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
7336d9a42beSaurel32                       fpsr |= BIT_IXC;
7346d9a42beSaurel32                     if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
7356d9a42beSaurel32                       fpsr |= BIT_UFC;
7366d9a42beSaurel32                     if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
7376d9a42beSaurel32                       fpsr |= BIT_OFC;
7386d9a42beSaurel32                     if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
7396d9a42beSaurel32                       fpsr |= BIT_DZC;
7406d9a42beSaurel32                     if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
7416d9a42beSaurel32                       fpsr |= BIT_IOC;
7426d9a42beSaurel32                     ts->fpa.fpsr=fpsr;
7436d9a42beSaurel32                 } else { /* everything OK */
744c6981055Sbellard                     /* increment PC */
745c6981055Sbellard                     env->regs[15] += 4;
746c6981055Sbellard                 }
747c6981055Sbellard             }
748b346ff46Sbellard             break;
749b346ff46Sbellard         case EXCP_SWI:
75006c949e6Spbrook         case EXCP_BKPT:
751b346ff46Sbellard             {
752ce4defa0Spbrook                 env->eabi = 1;
753b346ff46Sbellard                 /* system call */
75406c949e6Spbrook                 if (trapnr == EXCP_BKPT) {
75506c949e6Spbrook                     if (env->thumb) {
7562f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
757d8fd2954SPaul Brook                         get_user_code_u16(insn, env->regs[15], env->bswap_code);
75806c949e6Spbrook                         n = insn & 0xff;
75906c949e6Spbrook                         env->regs[15] += 2;
76006c949e6Spbrook                     } else {
7612f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
762d8fd2954SPaul Brook                         get_user_code_u32(insn, env->regs[15], env->bswap_code);
76306c949e6Spbrook                         n = (insn & 0xf) | ((insn >> 4) & 0xff0);
76406c949e6Spbrook                         env->regs[15] += 4;
76506c949e6Spbrook                     }
76606c949e6Spbrook                 } else {
767192c7bd9Sbellard                     if (env->thumb) {
7682f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
769d8fd2954SPaul Brook                         get_user_code_u16(insn, env->regs[15] - 2,
770d8fd2954SPaul Brook                                           env->bswap_code);
771192c7bd9Sbellard                         n = insn & 0xff;
772192c7bd9Sbellard                     } else {
7732f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
774d8fd2954SPaul Brook                         get_user_code_u32(insn, env->regs[15] - 4,
775d8fd2954SPaul Brook                                           env->bswap_code);
776b346ff46Sbellard                         n = insn & 0xffffff;
777192c7bd9Sbellard                     }
77806c949e6Spbrook                 }
779192c7bd9Sbellard 
7806f1f31c0Sbellard                 if (n == ARM_NR_cacheflush) {
781dcfd14b3SBlue Swirl                     /* nop */
782a4f81979Sbellard                 } else if (n == ARM_NR_semihosting
783a4f81979Sbellard                            || n == ARM_NR_thumb_semihosting) {
784a4f81979Sbellard                     env->regs[0] = do_arm_semihosting (env);
7853a1363acSAlexander Graf                 } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
786b346ff46Sbellard                     /* linux syscall */
787ce4defa0Spbrook                     if (env->thumb || n == 0) {
788192c7bd9Sbellard                         n = env->regs[7];
789192c7bd9Sbellard                     } else {
790b346ff46Sbellard                         n -= ARM_SYSCALL_BASE;
791ce4defa0Spbrook                         env->eabi = 0;
792192c7bd9Sbellard                     }
793fbb4a2e3Spbrook                     if ( n > ARM_NR_BASE) {
794fbb4a2e3Spbrook                         switch (n) {
795fbb4a2e3Spbrook                         case ARM_NR_cacheflush:
796dcfd14b3SBlue Swirl                             /* nop */
797fbb4a2e3Spbrook                             break;
798fbb4a2e3Spbrook                         case ARM_NR_set_tls:
799fbb4a2e3Spbrook                             cpu_set_tls(env, env->regs[0]);
800fbb4a2e3Spbrook                             env->regs[0] = 0;
801fbb4a2e3Spbrook                             break;
802d5355087SHunter Laux                         case ARM_NR_breakpoint:
803d5355087SHunter Laux                             env->regs[15] -= env->thumb ? 2 : 4;
804d5355087SHunter Laux                             goto excp_debug;
805fbb4a2e3Spbrook                         default:
806fbb4a2e3Spbrook                             gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
807fbb4a2e3Spbrook                                      n);
808fbb4a2e3Spbrook                             env->regs[0] = -TARGET_ENOSYS;
809fbb4a2e3Spbrook                             break;
810fbb4a2e3Spbrook                         }
811fbb4a2e3Spbrook                     } else {
812b346ff46Sbellard                         env->regs[0] = do_syscall(env,
813b346ff46Sbellard                                                   n,
814b346ff46Sbellard                                                   env->regs[0],
815b346ff46Sbellard                                                   env->regs[1],
816b346ff46Sbellard                                                   env->regs[2],
817b346ff46Sbellard                                                   env->regs[3],
818b346ff46Sbellard                                                   env->regs[4],
8195945cfcbSPeter Maydell                                                   env->regs[5],
8205945cfcbSPeter Maydell                                                   0, 0);
821fbb4a2e3Spbrook                     }
822b346ff46Sbellard                 } else {
823b346ff46Sbellard                     goto error;
824b346ff46Sbellard                 }
825b346ff46Sbellard             }
826b346ff46Sbellard             break;
82743fff238Sbellard         case EXCP_INTERRUPT:
82843fff238Sbellard             /* just indicate that signals should be handled asap */
82943fff238Sbellard             break;
830abf1172fSPeter Maydell         case EXCP_STREX:
831abf1172fSPeter Maydell             if (!do_strex(env)) {
832abf1172fSPeter Maydell                 break;
833abf1172fSPeter Maydell             }
834abf1172fSPeter Maydell             /* fall through for segv */
83568016c62Sbellard         case EXCP_PREFETCH_ABORT:
83668016c62Sbellard         case EXCP_DATA_ABORT:
837abf1172fSPeter Maydell             addr = env->exception.vaddress;
83868016c62Sbellard             {
839a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGSEGV;
84068016c62Sbellard                 info.si_errno = 0;
84168016c62Sbellard                 /* XXX: check env->error_code */
84268016c62Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
843b5ff1b31Sbellard                 info._sifields._sigfault._addr = addr;
844624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
84568016c62Sbellard             }
84668016c62Sbellard             break;
8471fddef4bSbellard         case EXCP_DEBUG:
848d5355087SHunter Laux         excp_debug:
8491fddef4bSbellard             {
8501fddef4bSbellard                 int sig;
8511fddef4bSbellard 
852db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
8531fddef4bSbellard                 if (sig)
8541fddef4bSbellard                   {
8551fddef4bSbellard                     info.si_signo = sig;
8561fddef4bSbellard                     info.si_errno = 0;
8571fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
858624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
8591fddef4bSbellard                   }
8601fddef4bSbellard             }
8611fddef4bSbellard             break;
862fbb4a2e3Spbrook         case EXCP_KERNEL_TRAP:
863fbb4a2e3Spbrook             if (do_kernel_trap(env))
864fbb4a2e3Spbrook               goto error;
865fbb4a2e3Spbrook             break;
866b346ff46Sbellard         default:
867b346ff46Sbellard         error:
868b346ff46Sbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
869b346ff46Sbellard                     trapnr);
870878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
871b346ff46Sbellard             abort();
872b346ff46Sbellard         }
873b346ff46Sbellard         process_pending_signals(env);
874b346ff46Sbellard     }
875b346ff46Sbellard }
876b346ff46Sbellard 
8771861c454SPeter Maydell #else
8781861c454SPeter Maydell 
879fa2ef212SMichael Matz /*
880fa2ef212SMichael Matz  * Handle AArch64 store-release exclusive
881fa2ef212SMichael Matz  *
882fa2ef212SMichael Matz  * rs = gets the status result of store exclusive
883fa2ef212SMichael Matz  * rt = is the register that is stored
884fa2ef212SMichael Matz  * rt2 = is the second register store (in STP)
885fa2ef212SMichael Matz  *
886fa2ef212SMichael Matz  */
887fa2ef212SMichael Matz static int do_strex_a64(CPUARMState *env)
888fa2ef212SMichael Matz {
889fa2ef212SMichael Matz     uint64_t val;
890fa2ef212SMichael Matz     int size;
891fa2ef212SMichael Matz     bool is_pair;
892fa2ef212SMichael Matz     int rc = 1;
893fa2ef212SMichael Matz     int segv = 0;
894fa2ef212SMichael Matz     uint64_t addr;
895fa2ef212SMichael Matz     int rs, rt, rt2;
896fa2ef212SMichael Matz 
897fa2ef212SMichael Matz     start_exclusive();
898fa2ef212SMichael Matz     /* size | is_pair << 2 | (rs << 4) | (rt << 9) | (rt2 << 14)); */
899fa2ef212SMichael Matz     size = extract32(env->exclusive_info, 0, 2);
900fa2ef212SMichael Matz     is_pair = extract32(env->exclusive_info, 2, 1);
901fa2ef212SMichael Matz     rs = extract32(env->exclusive_info, 4, 5);
902fa2ef212SMichael Matz     rt = extract32(env->exclusive_info, 9, 5);
903fa2ef212SMichael Matz     rt2 = extract32(env->exclusive_info, 14, 5);
904fa2ef212SMichael Matz 
905fa2ef212SMichael Matz     addr = env->exclusive_addr;
906fa2ef212SMichael Matz 
907fa2ef212SMichael Matz     if (addr != env->exclusive_test) {
908fa2ef212SMichael Matz         goto finish;
909fa2ef212SMichael Matz     }
910fa2ef212SMichael Matz 
911fa2ef212SMichael Matz     switch (size) {
912fa2ef212SMichael Matz     case 0:
913fa2ef212SMichael Matz         segv = get_user_u8(val, addr);
914fa2ef212SMichael Matz         break;
915fa2ef212SMichael Matz     case 1:
916fa2ef212SMichael Matz         segv = get_user_u16(val, addr);
917fa2ef212SMichael Matz         break;
918fa2ef212SMichael Matz     case 2:
919fa2ef212SMichael Matz         segv = get_user_u32(val, addr);
920fa2ef212SMichael Matz         break;
921fa2ef212SMichael Matz     case 3:
922fa2ef212SMichael Matz         segv = get_user_u64(val, addr);
923fa2ef212SMichael Matz         break;
924fa2ef212SMichael Matz     default:
925fa2ef212SMichael Matz         abort();
926fa2ef212SMichael Matz     }
927fa2ef212SMichael Matz     if (segv) {
928abf1172fSPeter Maydell         env->exception.vaddress = addr;
929fa2ef212SMichael Matz         goto error;
930fa2ef212SMichael Matz     }
931fa2ef212SMichael Matz     if (val != env->exclusive_val) {
932fa2ef212SMichael Matz         goto finish;
933fa2ef212SMichael Matz     }
934fa2ef212SMichael Matz     if (is_pair) {
935fa2ef212SMichael Matz         if (size == 2) {
936fa2ef212SMichael Matz             segv = get_user_u32(val, addr + 4);
937fa2ef212SMichael Matz         } else {
938fa2ef212SMichael Matz             segv = get_user_u64(val, addr + 8);
939fa2ef212SMichael Matz         }
940fa2ef212SMichael Matz         if (segv) {
941abf1172fSPeter Maydell             env->exception.vaddress = addr + (size == 2 ? 4 : 8);
942fa2ef212SMichael Matz             goto error;
943fa2ef212SMichael Matz         }
944fa2ef212SMichael Matz         if (val != env->exclusive_high) {
945fa2ef212SMichael Matz             goto finish;
946fa2ef212SMichael Matz         }
947fa2ef212SMichael Matz     }
9482ea5a2caSJanne Grunau     /* handle the zero register */
9492ea5a2caSJanne Grunau     val = rt == 31 ? 0 : env->xregs[rt];
950fa2ef212SMichael Matz     switch (size) {
951fa2ef212SMichael Matz     case 0:
952fa2ef212SMichael Matz         segv = put_user_u8(val, addr);
953fa2ef212SMichael Matz         break;
954fa2ef212SMichael Matz     case 1:
955fa2ef212SMichael Matz         segv = put_user_u16(val, addr);
956fa2ef212SMichael Matz         break;
957fa2ef212SMichael Matz     case 2:
958fa2ef212SMichael Matz         segv = put_user_u32(val, addr);
959fa2ef212SMichael Matz         break;
960fa2ef212SMichael Matz     case 3:
961fa2ef212SMichael Matz         segv = put_user_u64(val, addr);
962fa2ef212SMichael Matz         break;
963fa2ef212SMichael Matz     }
964fa2ef212SMichael Matz     if (segv) {
965fa2ef212SMichael Matz         goto error;
966fa2ef212SMichael Matz     }
967fa2ef212SMichael Matz     if (is_pair) {
9682ea5a2caSJanne Grunau         /* handle the zero register */
9692ea5a2caSJanne Grunau         val = rt2 == 31 ? 0 : env->xregs[rt2];
970fa2ef212SMichael Matz         if (size == 2) {
971fa2ef212SMichael Matz             segv = put_user_u32(val, addr + 4);
972fa2ef212SMichael Matz         } else {
973fa2ef212SMichael Matz             segv = put_user_u64(val, addr + 8);
974fa2ef212SMichael Matz         }
975fa2ef212SMichael Matz         if (segv) {
976abf1172fSPeter Maydell             env->exception.vaddress = addr + (size == 2 ? 4 : 8);
977fa2ef212SMichael Matz             goto error;
978fa2ef212SMichael Matz         }
979fa2ef212SMichael Matz     }
980fa2ef212SMichael Matz     rc = 0;
981fa2ef212SMichael Matz finish:
982fa2ef212SMichael Matz     env->pc += 4;
983fa2ef212SMichael Matz     /* rs == 31 encodes a write to the ZR, thus throwing away
984fa2ef212SMichael Matz      * the status return. This is rather silly but valid.
985fa2ef212SMichael Matz      */
986fa2ef212SMichael Matz     if (rs < 31) {
987fa2ef212SMichael Matz         env->xregs[rs] = rc;
988fa2ef212SMichael Matz     }
989fa2ef212SMichael Matz error:
990fa2ef212SMichael Matz     /* instruction faulted, PC does not advance */
991fa2ef212SMichael Matz     /* either way a strex releases any exclusive lock we have */
992fa2ef212SMichael Matz     env->exclusive_addr = -1;
993fa2ef212SMichael Matz     end_exclusive();
994fa2ef212SMichael Matz     return segv;
995fa2ef212SMichael Matz }
996fa2ef212SMichael Matz 
9971861c454SPeter Maydell /* AArch64 main loop */
9981861c454SPeter Maydell void cpu_loop(CPUARMState *env)
9991861c454SPeter Maydell {
10001861c454SPeter Maydell     CPUState *cs = CPU(arm_env_get_cpu(env));
10011861c454SPeter Maydell     int trapnr, sig;
10021861c454SPeter Maydell     target_siginfo_t info;
10031861c454SPeter Maydell 
10041861c454SPeter Maydell     for (;;) {
10051861c454SPeter Maydell         cpu_exec_start(cs);
1006ea3e9847SPeter Crosthwaite         trapnr = cpu_arm_exec(cs);
10071861c454SPeter Maydell         cpu_exec_end(cs);
10081861c454SPeter Maydell 
10091861c454SPeter Maydell         switch (trapnr) {
10101861c454SPeter Maydell         case EXCP_SWI:
10111861c454SPeter Maydell             env->xregs[0] = do_syscall(env,
10121861c454SPeter Maydell                                        env->xregs[8],
10131861c454SPeter Maydell                                        env->xregs[0],
10141861c454SPeter Maydell                                        env->xregs[1],
10151861c454SPeter Maydell                                        env->xregs[2],
10161861c454SPeter Maydell                                        env->xregs[3],
10171861c454SPeter Maydell                                        env->xregs[4],
10181861c454SPeter Maydell                                        env->xregs[5],
10191861c454SPeter Maydell                                        0, 0);
10201861c454SPeter Maydell             break;
10211861c454SPeter Maydell         case EXCP_INTERRUPT:
10221861c454SPeter Maydell             /* just indicate that signals should be handled asap */
10231861c454SPeter Maydell             break;
10241861c454SPeter Maydell         case EXCP_UDEF:
1025a86b3c64SChen Gang S             info.si_signo = TARGET_SIGILL;
10261861c454SPeter Maydell             info.si_errno = 0;
10271861c454SPeter Maydell             info.si_code = TARGET_ILL_ILLOPN;
10281861c454SPeter Maydell             info._sifields._sigfault._addr = env->pc;
10291861c454SPeter Maydell             queue_signal(env, info.si_signo, &info);
10301861c454SPeter Maydell             break;
1031abf1172fSPeter Maydell         case EXCP_STREX:
1032abf1172fSPeter Maydell             if (!do_strex_a64(env)) {
1033abf1172fSPeter Maydell                 break;
1034abf1172fSPeter Maydell             }
1035abf1172fSPeter Maydell             /* fall through for segv */
10361861c454SPeter Maydell         case EXCP_PREFETCH_ABORT:
10371861c454SPeter Maydell         case EXCP_DATA_ABORT:
1038a86b3c64SChen Gang S             info.si_signo = TARGET_SIGSEGV;
10391861c454SPeter Maydell             info.si_errno = 0;
10401861c454SPeter Maydell             /* XXX: check env->error_code */
10411861c454SPeter Maydell             info.si_code = TARGET_SEGV_MAPERR;
1042686581adSRiku Voipio             info._sifields._sigfault._addr = env->exception.vaddress;
10431861c454SPeter Maydell             queue_signal(env, info.si_signo, &info);
10441861c454SPeter Maydell             break;
10451861c454SPeter Maydell         case EXCP_DEBUG:
10461861c454SPeter Maydell         case EXCP_BKPT:
10471861c454SPeter Maydell             sig = gdb_handlesig(cs, TARGET_SIGTRAP);
10481861c454SPeter Maydell             if (sig) {
10491861c454SPeter Maydell                 info.si_signo = sig;
10501861c454SPeter Maydell                 info.si_errno = 0;
10511861c454SPeter Maydell                 info.si_code = TARGET_TRAP_BRKPT;
10521861c454SPeter Maydell                 queue_signal(env, info.si_signo, &info);
10531861c454SPeter Maydell             }
10541861c454SPeter Maydell             break;
10558012c84fSPeter Maydell         case EXCP_SEMIHOST:
10568012c84fSPeter Maydell             env->xregs[0] = do_arm_semihosting(env);
10578012c84fSPeter Maydell             break;
10581861c454SPeter Maydell         default:
10591861c454SPeter Maydell             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
10601861c454SPeter Maydell                     trapnr);
10611861c454SPeter Maydell             cpu_dump_state(cs, stderr, fprintf, 0);
10621861c454SPeter Maydell             abort();
10631861c454SPeter Maydell         }
10641861c454SPeter Maydell         process_pending_signals(env);
1065fa2ef212SMichael Matz         /* Exception return on AArch64 always clears the exclusive monitor,
1066fa2ef212SMichael Matz          * so any return to running guest code implies this.
1067fa2ef212SMichael Matz          * A strex (successful or otherwise) also clears the monitor, so
1068fa2ef212SMichael Matz          * we don't need to specialcase EXCP_STREX.
1069fa2ef212SMichael Matz          */
1070fa2ef212SMichael Matz         env->exclusive_addr = -1;
10711861c454SPeter Maydell     }
10721861c454SPeter Maydell }
10731861c454SPeter Maydell #endif /* ndef TARGET_ABI32 */
10741861c454SPeter Maydell 
1075b346ff46Sbellard #endif
10761b6b029eSbellard 
1077d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32
1078d2fbca94SGuan Xuetao 
107905390248SAndreas Färber void cpu_loop(CPUUniCore32State *env)
1080d2fbca94SGuan Xuetao {
10810315c31cSAndreas Färber     CPUState *cs = CPU(uc32_env_get_cpu(env));
1082d2fbca94SGuan Xuetao     int trapnr;
1083d2fbca94SGuan Xuetao     unsigned int n, insn;
1084d2fbca94SGuan Xuetao     target_siginfo_t info;
1085d2fbca94SGuan Xuetao 
1086d2fbca94SGuan Xuetao     for (;;) {
10870315c31cSAndreas Färber         cpu_exec_start(cs);
1088ea3e9847SPeter Crosthwaite         trapnr = uc32_cpu_exec(cs);
10890315c31cSAndreas Färber         cpu_exec_end(cs);
1090d2fbca94SGuan Xuetao         switch (trapnr) {
1091d2fbca94SGuan Xuetao         case UC32_EXCP_PRIV:
1092d2fbca94SGuan Xuetao             {
1093d2fbca94SGuan Xuetao                 /* system call */
1094d2fbca94SGuan Xuetao                 get_user_u32(insn, env->regs[31] - 4);
1095d2fbca94SGuan Xuetao                 n = insn & 0xffffff;
1096d2fbca94SGuan Xuetao 
1097d2fbca94SGuan Xuetao                 if (n >= UC32_SYSCALL_BASE) {
1098d2fbca94SGuan Xuetao                     /* linux syscall */
1099d2fbca94SGuan Xuetao                     n -= UC32_SYSCALL_BASE;
1100d2fbca94SGuan Xuetao                     if (n == UC32_SYSCALL_NR_set_tls) {
1101d2fbca94SGuan Xuetao                             cpu_set_tls(env, env->regs[0]);
1102d2fbca94SGuan Xuetao                             env->regs[0] = 0;
1103d2fbca94SGuan Xuetao                     } else {
1104d2fbca94SGuan Xuetao                         env->regs[0] = do_syscall(env,
1105d2fbca94SGuan Xuetao                                                   n,
1106d2fbca94SGuan Xuetao                                                   env->regs[0],
1107d2fbca94SGuan Xuetao                                                   env->regs[1],
1108d2fbca94SGuan Xuetao                                                   env->regs[2],
1109d2fbca94SGuan Xuetao                                                   env->regs[3],
1110d2fbca94SGuan Xuetao                                                   env->regs[4],
11115945cfcbSPeter Maydell                                                   env->regs[5],
11125945cfcbSPeter Maydell                                                   0, 0);
1113d2fbca94SGuan Xuetao                     }
1114d2fbca94SGuan Xuetao                 } else {
1115d2fbca94SGuan Xuetao                     goto error;
1116d2fbca94SGuan Xuetao                 }
1117d2fbca94SGuan Xuetao             }
1118d2fbca94SGuan Xuetao             break;
1119d48813ddSGuan Xuetao         case UC32_EXCP_DTRAP:
1120d48813ddSGuan Xuetao         case UC32_EXCP_ITRAP:
1121a86b3c64SChen Gang S             info.si_signo = TARGET_SIGSEGV;
1122d2fbca94SGuan Xuetao             info.si_errno = 0;
1123d2fbca94SGuan Xuetao             /* XXX: check env->error_code */
1124d2fbca94SGuan Xuetao             info.si_code = TARGET_SEGV_MAPERR;
1125d2fbca94SGuan Xuetao             info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
1126d2fbca94SGuan Xuetao             queue_signal(env, info.si_signo, &info);
1127d2fbca94SGuan Xuetao             break;
1128d2fbca94SGuan Xuetao         case EXCP_INTERRUPT:
1129d2fbca94SGuan Xuetao             /* just indicate that signals should be handled asap */
1130d2fbca94SGuan Xuetao             break;
1131d2fbca94SGuan Xuetao         case EXCP_DEBUG:
1132d2fbca94SGuan Xuetao             {
1133d2fbca94SGuan Xuetao                 int sig;
1134d2fbca94SGuan Xuetao 
1135db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
1136d2fbca94SGuan Xuetao                 if (sig) {
1137d2fbca94SGuan Xuetao                     info.si_signo = sig;
1138d2fbca94SGuan Xuetao                     info.si_errno = 0;
1139d2fbca94SGuan Xuetao                     info.si_code = TARGET_TRAP_BRKPT;
1140d2fbca94SGuan Xuetao                     queue_signal(env, info.si_signo, &info);
1141d2fbca94SGuan Xuetao                 }
1142d2fbca94SGuan Xuetao             }
1143d2fbca94SGuan Xuetao             break;
1144d2fbca94SGuan Xuetao         default:
1145d2fbca94SGuan Xuetao             goto error;
1146d2fbca94SGuan Xuetao         }
1147d2fbca94SGuan Xuetao         process_pending_signals(env);
1148d2fbca94SGuan Xuetao     }
1149d2fbca94SGuan Xuetao 
1150d2fbca94SGuan Xuetao error:
1151d2fbca94SGuan Xuetao     fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
1152878096eeSAndreas Färber     cpu_dump_state(cs, stderr, fprintf, 0);
1153d2fbca94SGuan Xuetao     abort();
1154d2fbca94SGuan Xuetao }
1155d2fbca94SGuan Xuetao #endif
1156d2fbca94SGuan Xuetao 
115793ac68bcSbellard #ifdef TARGET_SPARC
1158ed23fbd9Sblueswir1 #define SPARC64_STACK_BIAS 2047
115993ac68bcSbellard 
1160060366c5Sbellard //#define DEBUG_WIN
1161060366c5Sbellard 
11622623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info
11632623cbafSbellard    can be found at http://www.sics.se/~psm/sparcstack.html */
1164060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
1165060366c5Sbellard {
11661a14026eSblueswir1     index = (index + cwp * 16) % (16 * env->nwindows);
1167060366c5Sbellard     /* wrap handling : if cwp is on the last window, then we use the
1168060366c5Sbellard        registers 'after' the end */
11691a14026eSblueswir1     if (index < 8 && env->cwp == env->nwindows - 1)
11701a14026eSblueswir1         index += 16 * env->nwindows;
1171060366c5Sbellard     return index;
1172060366c5Sbellard }
1173060366c5Sbellard 
11742623cbafSbellard /* save the register window 'cwp1' */
11752623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1)
1176060366c5Sbellard {
11772623cbafSbellard     unsigned int i;
1178992f48a0Sblueswir1     abi_ulong sp_ptr;
1179060366c5Sbellard 
118053a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1181ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1182ed23fbd9Sblueswir1     if (sp_ptr & 3)
1183ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1184ed23fbd9Sblueswir1 #endif
1185060366c5Sbellard #if defined(DEBUG_WIN)
11862daf0284Sblueswir1     printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
11872daf0284Sblueswir1            sp_ptr, cwp1);
1188060366c5Sbellard #endif
11892623cbafSbellard     for(i = 0; i < 16; i++) {
11902f619698Sbellard         /* FIXME - what to do if put_user() fails? */
11912f619698Sbellard         put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1192992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
11932623cbafSbellard     }
1194060366c5Sbellard }
1195060366c5Sbellard 
1196060366c5Sbellard static void save_window(CPUSPARCState *env)
1197060366c5Sbellard {
11985ef54116Sbellard #ifndef TARGET_SPARC64
11992623cbafSbellard     unsigned int new_wim;
12001a14026eSblueswir1     new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
12011a14026eSblueswir1         ((1LL << env->nwindows) - 1);
12021a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
12032623cbafSbellard     env->wim = new_wim;
12045ef54116Sbellard #else
12051a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
12065ef54116Sbellard     env->cansave++;
12075ef54116Sbellard     env->canrestore--;
12085ef54116Sbellard #endif
1209060366c5Sbellard }
1210060366c5Sbellard 
1211060366c5Sbellard static void restore_window(CPUSPARCState *env)
1212060366c5Sbellard {
1213eda52953Sblueswir1 #ifndef TARGET_SPARC64
1214eda52953Sblueswir1     unsigned int new_wim;
1215eda52953Sblueswir1 #endif
1216eda52953Sblueswir1     unsigned int i, cwp1;
1217992f48a0Sblueswir1     abi_ulong sp_ptr;
1218060366c5Sbellard 
1219eda52953Sblueswir1 #ifndef TARGET_SPARC64
12201a14026eSblueswir1     new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
12211a14026eSblueswir1         ((1LL << env->nwindows) - 1);
1222eda52953Sblueswir1 #endif
1223060366c5Sbellard 
1224060366c5Sbellard     /* restore the invalid window */
12251a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
122653a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1227ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1228ed23fbd9Sblueswir1     if (sp_ptr & 3)
1229ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1230ed23fbd9Sblueswir1 #endif
1231060366c5Sbellard #if defined(DEBUG_WIN)
12322daf0284Sblueswir1     printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
12332daf0284Sblueswir1            sp_ptr, cwp1);
1234060366c5Sbellard #endif
12352623cbafSbellard     for(i = 0; i < 16; i++) {
12362f619698Sbellard         /* FIXME - what to do if get_user() fails? */
12372f619698Sbellard         get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1238992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
12392623cbafSbellard     }
12405ef54116Sbellard #ifdef TARGET_SPARC64
12415ef54116Sbellard     env->canrestore++;
12421a14026eSblueswir1     if (env->cleanwin < env->nwindows - 1)
12435ef54116Sbellard         env->cleanwin++;
12445ef54116Sbellard     env->cansave--;
1245eda52953Sblueswir1 #else
1246eda52953Sblueswir1     env->wim = new_wim;
12475ef54116Sbellard #endif
1248060366c5Sbellard }
1249060366c5Sbellard 
1250060366c5Sbellard static void flush_windows(CPUSPARCState *env)
1251060366c5Sbellard {
1252060366c5Sbellard     int offset, cwp1;
12532623cbafSbellard 
12542623cbafSbellard     offset = 1;
1255060366c5Sbellard     for(;;) {
1256060366c5Sbellard         /* if restore would invoke restore_window(), then we can stop */
12571a14026eSblueswir1         cwp1 = cpu_cwp_inc(env, env->cwp + offset);
1258eda52953Sblueswir1 #ifndef TARGET_SPARC64
1259060366c5Sbellard         if (env->wim & (1 << cwp1))
1260060366c5Sbellard             break;
1261eda52953Sblueswir1 #else
1262eda52953Sblueswir1         if (env->canrestore == 0)
1263eda52953Sblueswir1             break;
1264eda52953Sblueswir1         env->cansave++;
1265eda52953Sblueswir1         env->canrestore--;
1266eda52953Sblueswir1 #endif
12672623cbafSbellard         save_window_offset(env, cwp1);
1268060366c5Sbellard         offset++;
1269060366c5Sbellard     }
12701a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
1271eda52953Sblueswir1 #ifndef TARGET_SPARC64
1272eda52953Sblueswir1     /* set wim so that restore will reload the registers */
12732623cbafSbellard     env->wim = 1 << cwp1;
1274eda52953Sblueswir1 #endif
12752623cbafSbellard #if defined(DEBUG_WIN)
12762623cbafSbellard     printf("flush_windows: nb=%d\n", offset - 1);
127780a9d035Sbellard #endif
12782623cbafSbellard }
1279060366c5Sbellard 
128093ac68bcSbellard void cpu_loop (CPUSPARCState *env)
128193ac68bcSbellard {
1282878096eeSAndreas Färber     CPUState *cs = CPU(sparc_env_get_cpu(env));
12832cc20260SRichard Henderson     int trapnr;
12842cc20260SRichard Henderson     abi_long ret;
1285c227f099SAnthony Liguori     target_siginfo_t info;
128693ac68bcSbellard 
128793ac68bcSbellard     while (1) {
1288b040bc9cSPeter Maydell         cpu_exec_start(cs);
1289ea3e9847SPeter Crosthwaite         trapnr = cpu_sparc_exec(cs);
1290b040bc9cSPeter Maydell         cpu_exec_end(cs);
129193ac68bcSbellard 
129220132b96SRichard Henderson         /* Compute PSR before exposing state.  */
129320132b96SRichard Henderson         if (env->cc_op != CC_OP_FLAGS) {
129420132b96SRichard Henderson             cpu_get_psr(env);
129520132b96SRichard Henderson         }
129620132b96SRichard Henderson 
129793ac68bcSbellard         switch (trapnr) {
12985ef54116Sbellard #ifndef TARGET_SPARC64
1299060366c5Sbellard         case 0x88:
1300060366c5Sbellard         case 0x90:
13015ef54116Sbellard #else
1302cb33da57Sblueswir1         case 0x110:
13035ef54116Sbellard         case 0x16d:
13045ef54116Sbellard #endif
1305060366c5Sbellard             ret = do_syscall (env, env->gregs[1],
1306060366c5Sbellard                               env->regwptr[0], env->regwptr[1],
1307060366c5Sbellard                               env->regwptr[2], env->regwptr[3],
13085945cfcbSPeter Maydell                               env->regwptr[4], env->regwptr[5],
13095945cfcbSPeter Maydell                               0, 0);
13102cc20260SRichard Henderson             if ((abi_ulong)ret >= (abi_ulong)(-515)) {
1311992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
131227908725Sbellard                 env->xcc |= PSR_CARRY;
131327908725Sbellard #else
131493ac68bcSbellard                 env->psr |= PSR_CARRY;
131527908725Sbellard #endif
1316060366c5Sbellard                 ret = -ret;
1317060366c5Sbellard             } else {
1318992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
131927908725Sbellard                 env->xcc &= ~PSR_CARRY;
132027908725Sbellard #else
1321060366c5Sbellard                 env->psr &= ~PSR_CARRY;
132227908725Sbellard #endif
1323060366c5Sbellard             }
1324060366c5Sbellard             env->regwptr[0] = ret;
1325060366c5Sbellard             /* next instruction */
1326060366c5Sbellard             env->pc = env->npc;
1327060366c5Sbellard             env->npc = env->npc + 4;
1328060366c5Sbellard             break;
1329060366c5Sbellard         case 0x83: /* flush windows */
1330992f48a0Sblueswir1 #ifdef TARGET_ABI32
1331992f48a0Sblueswir1         case 0x103:
1332992f48a0Sblueswir1 #endif
13332623cbafSbellard             flush_windows(env);
1334060366c5Sbellard             /* next instruction */
1335060366c5Sbellard             env->pc = env->npc;
1336060366c5Sbellard             env->npc = env->npc + 4;
1337060366c5Sbellard             break;
13383475187dSbellard #ifndef TARGET_SPARC64
1339060366c5Sbellard         case TT_WIN_OVF: /* window overflow */
1340060366c5Sbellard             save_window(env);
1341060366c5Sbellard             break;
1342060366c5Sbellard         case TT_WIN_UNF: /* window underflow */
1343060366c5Sbellard             restore_window(env);
134493ac68bcSbellard             break;
134561ff6f58Sbellard         case TT_TFAULT:
134661ff6f58Sbellard         case TT_DFAULT:
134761ff6f58Sbellard             {
134859f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
134961ff6f58Sbellard                 info.si_errno = 0;
135061ff6f58Sbellard                 /* XXX: check env->error_code */
135161ff6f58Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
135261ff6f58Sbellard                 info._sifields._sigfault._addr = env->mmuregs[4];
1353624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
135461ff6f58Sbellard             }
135561ff6f58Sbellard             break;
13563475187dSbellard #else
13575ef54116Sbellard         case TT_SPILL: /* window overflow */
13585ef54116Sbellard             save_window(env);
13595ef54116Sbellard             break;
13605ef54116Sbellard         case TT_FILL: /* window underflow */
13615ef54116Sbellard             restore_window(env);
13625ef54116Sbellard             break;
13637f84a729Sblueswir1         case TT_TFAULT:
13647f84a729Sblueswir1         case TT_DFAULT:
13657f84a729Sblueswir1             {
136659f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
13677f84a729Sblueswir1                 info.si_errno = 0;
13687f84a729Sblueswir1                 /* XXX: check env->error_code */
13697f84a729Sblueswir1                 info.si_code = TARGET_SEGV_MAPERR;
13707f84a729Sblueswir1                 if (trapnr == TT_DFAULT)
13717f84a729Sblueswir1                     info._sifields._sigfault._addr = env->dmmuregs[4];
13727f84a729Sblueswir1                 else
13738194f35aSIgor Kovalenko                     info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
1374624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
13757f84a729Sblueswir1             }
13767f84a729Sblueswir1             break;
137727524dc3Sbellard #ifndef TARGET_ABI32
13785bfb56b2Sblueswir1         case 0x16e:
13795bfb56b2Sblueswir1             flush_windows(env);
13805bfb56b2Sblueswir1             sparc64_get_context(env);
13815bfb56b2Sblueswir1             break;
13825bfb56b2Sblueswir1         case 0x16f:
13835bfb56b2Sblueswir1             flush_windows(env);
13845bfb56b2Sblueswir1             sparc64_set_context(env);
13855bfb56b2Sblueswir1             break;
13863475187dSbellard #endif
138727524dc3Sbellard #endif
138848dc41ebSbellard         case EXCP_INTERRUPT:
138948dc41ebSbellard             /* just indicate that signals should be handled asap */
1390e80cfcfcSbellard             break;
139175f22e4eSRichard Henderson         case TT_ILL_INSN:
139275f22e4eSRichard Henderson             {
139375f22e4eSRichard Henderson                 info.si_signo = TARGET_SIGILL;
139475f22e4eSRichard Henderson                 info.si_errno = 0;
139575f22e4eSRichard Henderson                 info.si_code = TARGET_ILL_ILLOPC;
139675f22e4eSRichard Henderson                 info._sifields._sigfault._addr = env->pc;
139775f22e4eSRichard Henderson                 queue_signal(env, info.si_signo, &info);
139875f22e4eSRichard Henderson             }
139975f22e4eSRichard Henderson             break;
14001fddef4bSbellard         case EXCP_DEBUG:
14011fddef4bSbellard             {
14021fddef4bSbellard                 int sig;
14031fddef4bSbellard 
1404db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
14051fddef4bSbellard                 if (sig)
14061fddef4bSbellard                   {
14071fddef4bSbellard                     info.si_signo = sig;
14081fddef4bSbellard                     info.si_errno = 0;
14091fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
1410624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
14111fddef4bSbellard                   }
14121fddef4bSbellard             }
14131fddef4bSbellard             break;
141493ac68bcSbellard         default:
1415060366c5Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
1416878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
14174d1275c2SRiku Voipio             exit(EXIT_FAILURE);
141893ac68bcSbellard         }
141993ac68bcSbellard         process_pending_signals (env);
142093ac68bcSbellard     }
142193ac68bcSbellard }
142293ac68bcSbellard 
142393ac68bcSbellard #endif
142493ac68bcSbellard 
142567867308Sbellard #ifdef TARGET_PPC
142605390248SAndreas Färber static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
14279fddaa0cSbellard {
14287d6b1daeSLaurent Vivier     return cpu_get_real_ticks();
14299fddaa0cSbellard }
14309fddaa0cSbellard 
143105390248SAndreas Färber uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
14329fddaa0cSbellard {
1433e3ea6529SAlexander Graf     return cpu_ppc_get_tb(env);
14349fddaa0cSbellard }
14359fddaa0cSbellard 
143605390248SAndreas Färber uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
14379fddaa0cSbellard {
14389fddaa0cSbellard     return cpu_ppc_get_tb(env) >> 32;
14399fddaa0cSbellard }
14409fddaa0cSbellard 
144105390248SAndreas Färber uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
14429fddaa0cSbellard {
1443b711de95SAurelien Jarno     return cpu_ppc_get_tb(env);
14449fddaa0cSbellard }
14459fddaa0cSbellard 
144605390248SAndreas Färber uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
14479fddaa0cSbellard {
1448a062e36cSj_mayer     return cpu_ppc_get_tb(env) >> 32;
14499fddaa0cSbellard }
14509fddaa0cSbellard 
145105390248SAndreas Färber uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
145276a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_load_tbu") ));
145376a66253Sj_mayer 
145405390248SAndreas Färber uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
14559fddaa0cSbellard {
145676a66253Sj_mayer     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
14579fddaa0cSbellard }
14589fddaa0cSbellard 
1459a750fc0bSj_mayer /* XXX: to be fixed */
146073b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
1461a750fc0bSj_mayer {
1462a750fc0bSj_mayer     return -1;
1463a750fc0bSj_mayer }
1464a750fc0bSj_mayer 
146573b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
1466a750fc0bSj_mayer {
1467a750fc0bSj_mayer     return -1;
1468a750fc0bSj_mayer }
1469a750fc0bSj_mayer 
1470001faf32SBlue Swirl #define EXCP_DUMP(env, fmt, ...)                                        \
1471e1833e1fSj_mayer do {                                                                    \
1472a0762859SAndreas Färber     CPUState *cs = ENV_GET_CPU(env);                                    \
1473001faf32SBlue Swirl     fprintf(stderr, fmt , ## __VA_ARGS__);                              \
1474a0762859SAndreas Färber     cpu_dump_state(cs, stderr, fprintf, 0);                             \
1475001faf32SBlue Swirl     qemu_log(fmt, ## __VA_ARGS__);                                      \
1476eeacee4dSBlue Swirl     if (qemu_log_enabled()) {                                           \
1477a0762859SAndreas Färber         log_cpu_state(cs, 0);                                           \
1478eeacee4dSBlue Swirl     }                                                                   \
1479e1833e1fSj_mayer } while (0)
1480e1833e1fSj_mayer 
148156f066bbSNathan Froyd static int do_store_exclusive(CPUPPCState *env)
148256f066bbSNathan Froyd {
148356f066bbSNathan Froyd     target_ulong addr;
148456f066bbSNathan Froyd     target_ulong page_addr;
1485e22c357bSDoug Kwan     target_ulong val, val2 __attribute__((unused)) = 0;
148656f066bbSNathan Froyd     int flags;
148756f066bbSNathan Froyd     int segv = 0;
148856f066bbSNathan Froyd 
148956f066bbSNathan Froyd     addr = env->reserve_ea;
149056f066bbSNathan Froyd     page_addr = addr & TARGET_PAGE_MASK;
149156f066bbSNathan Froyd     start_exclusive();
149256f066bbSNathan Froyd     mmap_lock();
149356f066bbSNathan Froyd     flags = page_get_flags(page_addr);
149456f066bbSNathan Froyd     if ((flags & PAGE_READ) == 0) {
149556f066bbSNathan Froyd         segv = 1;
149656f066bbSNathan Froyd     } else {
149756f066bbSNathan Froyd         int reg = env->reserve_info & 0x1f;
14984b1daa72STom Musta         int size = env->reserve_info >> 5;
149956f066bbSNathan Froyd         int stored = 0;
150056f066bbSNathan Froyd 
150156f066bbSNathan Froyd         if (addr == env->reserve_addr) {
150256f066bbSNathan Froyd             switch (size) {
150356f066bbSNathan Froyd             case 1: segv = get_user_u8(val, addr); break;
150456f066bbSNathan Froyd             case 2: segv = get_user_u16(val, addr); break;
150556f066bbSNathan Froyd             case 4: segv = get_user_u32(val, addr); break;
150656f066bbSNathan Froyd #if defined(TARGET_PPC64)
150756f066bbSNathan Froyd             case 8: segv = get_user_u64(val, addr); break;
150827b95bfeSTom Musta             case 16: {
150927b95bfeSTom Musta                 segv = get_user_u64(val, addr);
151027b95bfeSTom Musta                 if (!segv) {
151127b95bfeSTom Musta                     segv = get_user_u64(val2, addr + 8);
151227b95bfeSTom Musta                 }
151327b95bfeSTom Musta                 break;
151427b95bfeSTom Musta             }
151556f066bbSNathan Froyd #endif
151656f066bbSNathan Froyd             default: abort();
151756f066bbSNathan Froyd             }
151856f066bbSNathan Froyd             if (!segv && val == env->reserve_val) {
151956f066bbSNathan Froyd                 val = env->gpr[reg];
152056f066bbSNathan Froyd                 switch (size) {
152156f066bbSNathan Froyd                 case 1: segv = put_user_u8(val, addr); break;
152256f066bbSNathan Froyd                 case 2: segv = put_user_u16(val, addr); break;
152356f066bbSNathan Froyd                 case 4: segv = put_user_u32(val, addr); break;
152456f066bbSNathan Froyd #if defined(TARGET_PPC64)
152556f066bbSNathan Froyd                 case 8: segv = put_user_u64(val, addr); break;
152627b95bfeSTom Musta                 case 16: {
152727b95bfeSTom Musta                     if (val2 == env->reserve_val2) {
1528e22c357bSDoug Kwan                         if (msr_le) {
1529e22c357bSDoug Kwan                             val2 = val;
1530e22c357bSDoug Kwan                             val = env->gpr[reg+1];
1531e22c357bSDoug Kwan                         } else {
1532e22c357bSDoug Kwan                             val2 = env->gpr[reg+1];
1533e22c357bSDoug Kwan                         }
153427b95bfeSTom Musta                         segv = put_user_u64(val, addr);
153527b95bfeSTom Musta                         if (!segv) {
153627b95bfeSTom Musta                             segv = put_user_u64(val2, addr + 8);
153727b95bfeSTom Musta                         }
153827b95bfeSTom Musta                     }
153927b95bfeSTom Musta                     break;
154027b95bfeSTom Musta                 }
154156f066bbSNathan Froyd #endif
154256f066bbSNathan Froyd                 default: abort();
154356f066bbSNathan Froyd                 }
154456f066bbSNathan Froyd                 if (!segv) {
154556f066bbSNathan Froyd                     stored = 1;
154656f066bbSNathan Froyd                 }
154756f066bbSNathan Froyd             }
154856f066bbSNathan Froyd         }
154956f066bbSNathan Froyd         env->crf[0] = (stored << 1) | xer_so;
155056f066bbSNathan Froyd         env->reserve_addr = (target_ulong)-1;
155156f066bbSNathan Froyd     }
155256f066bbSNathan Froyd     if (!segv) {
155356f066bbSNathan Froyd         env->nip += 4;
155456f066bbSNathan Froyd     }
155556f066bbSNathan Froyd     mmap_unlock();
155656f066bbSNathan Froyd     end_exclusive();
155756f066bbSNathan Froyd     return segv;
155856f066bbSNathan Froyd }
155956f066bbSNathan Froyd 
156067867308Sbellard void cpu_loop(CPUPPCState *env)
156167867308Sbellard {
15620315c31cSAndreas Färber     CPUState *cs = CPU(ppc_env_get_cpu(env));
1563c227f099SAnthony Liguori     target_siginfo_t info;
156461190b14Sbellard     int trapnr;
15659e0e2f96SRichard Henderson     target_ulong ret;
156667867308Sbellard 
156767867308Sbellard     for(;;) {
15680315c31cSAndreas Färber         cpu_exec_start(cs);
1569ea3e9847SPeter Crosthwaite         trapnr = cpu_ppc_exec(cs);
15700315c31cSAndreas Färber         cpu_exec_end(cs);
157167867308Sbellard         switch(trapnr) {
1572e1833e1fSj_mayer         case POWERPC_EXCP_NONE:
1573e1833e1fSj_mayer             /* Just go on */
157467867308Sbellard             break;
1575e1833e1fSj_mayer         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
1576a47dddd7SAndreas Färber             cpu_abort(cs, "Critical interrupt while in user mode. "
1577e1833e1fSj_mayer                       "Aborting\n");
1578e1833e1fSj_mayer             break;
1579e1833e1fSj_mayer         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
1580a47dddd7SAndreas Färber             cpu_abort(cs, "Machine check exception while in user mode. "
1581e1833e1fSj_mayer                       "Aborting\n");
1582e1833e1fSj_mayer             break;
1583e1833e1fSj_mayer         case POWERPC_EXCP_DSI:      /* Data storage exception                */
158490e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
1585e1833e1fSj_mayer                       env->spr[SPR_DAR]);
1586e1833e1fSj_mayer             /* XXX: check this. Seems bugged */
1587e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1588e1833e1fSj_mayer             case 0x40000000:
1589e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1590e1833e1fSj_mayer                 info.si_errno = 0;
1591e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1592e1833e1fSj_mayer                 break;
1593e1833e1fSj_mayer             case 0x04000000:
1594e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1595e1833e1fSj_mayer                 info.si_errno = 0;
1596e1833e1fSj_mayer                 info.si_code = TARGET_ILL_ILLADR;
1597e1833e1fSj_mayer                 break;
1598e1833e1fSj_mayer             case 0x08000000:
1599e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1600e1833e1fSj_mayer                 info.si_errno = 0;
1601e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1602e1833e1fSj_mayer                 break;
1603e1833e1fSj_mayer             default:
1604e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1605e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1606e1833e1fSj_mayer                           env->error_code);
1607e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1608e1833e1fSj_mayer                 info.si_errno = 0;
1609e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1610e1833e1fSj_mayer                 break;
1611e1833e1fSj_mayer             }
1612e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip;
1613624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1614e1833e1fSj_mayer             break;
1615e1833e1fSj_mayer         case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
161690e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
161790e189ecSBlue Swirl                       "\n", env->spr[SPR_SRR0]);
1618e1833e1fSj_mayer             /* XXX: check this */
1619e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1620e1833e1fSj_mayer             case 0x40000000:
1621e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1622e1833e1fSj_mayer             info.si_errno = 0;
1623e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1624e1833e1fSj_mayer                 break;
1625e1833e1fSj_mayer             case 0x10000000:
1626e1833e1fSj_mayer             case 0x08000000:
1627e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1628e1833e1fSj_mayer                 info.si_errno = 0;
1629e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1630e1833e1fSj_mayer                 break;
1631e1833e1fSj_mayer             default:
1632e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1633e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1634e1833e1fSj_mayer                           env->error_code);
1635e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1636e1833e1fSj_mayer                 info.si_errno = 0;
1637e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1638e1833e1fSj_mayer                 break;
1639e1833e1fSj_mayer             }
1640e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1641624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1642e1833e1fSj_mayer             break;
1643e1833e1fSj_mayer         case POWERPC_EXCP_EXTERNAL: /* External input                        */
1644a47dddd7SAndreas Färber             cpu_abort(cs, "External interrupt while in user mode. "
1645e1833e1fSj_mayer                       "Aborting\n");
1646e1833e1fSj_mayer             break;
1647e1833e1fSj_mayer         case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
1648e1833e1fSj_mayer             EXCP_DUMP(env, "Unaligned memory access\n");
1649e1833e1fSj_mayer             /* XXX: check this */
1650e1833e1fSj_mayer             info.si_signo = TARGET_SIGBUS;
1651e1833e1fSj_mayer             info.si_errno = 0;
1652e1833e1fSj_mayer             info.si_code = TARGET_BUS_ADRALN;
16536bb9a0a9SAnton Blanchard             info._sifields._sigfault._addr = env->nip;
1654624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1655e1833e1fSj_mayer             break;
1656e1833e1fSj_mayer         case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
1657e1833e1fSj_mayer             /* XXX: check this */
1658e1833e1fSj_mayer             switch (env->error_code & ~0xF) {
1659e1833e1fSj_mayer             case POWERPC_EXCP_FP:
1660e1833e1fSj_mayer                 EXCP_DUMP(env, "Floating point program exception\n");
1661e1833e1fSj_mayer                 info.si_signo = TARGET_SIGFPE;
1662e1833e1fSj_mayer                 info.si_errno = 0;
1663e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1664e1833e1fSj_mayer                 case POWERPC_EXCP_FP_OX:
1665e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTOVF;
1666e1833e1fSj_mayer                     break;
1667e1833e1fSj_mayer                 case POWERPC_EXCP_FP_UX:
1668e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTUND;
1669e1833e1fSj_mayer                     break;
1670e1833e1fSj_mayer                 case POWERPC_EXCP_FP_ZX:
1671e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXZDZ:
1672e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTDIV;
1673e1833e1fSj_mayer                     break;
1674e1833e1fSj_mayer                 case POWERPC_EXCP_FP_XX:
1675e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTRES;
1676e1833e1fSj_mayer                     break;
1677e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSOFT:
1678e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTINV;
1679e1833e1fSj_mayer                     break;
16807c58044cSj_mayer                 case POWERPC_EXCP_FP_VXSNAN:
1681e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXISI:
1682e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIDI:
1683e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIMZ:
1684e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXVC:
1685e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSQRT:
1686e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXCVI:
1687e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTSUB;
1688e1833e1fSj_mayer                     break;
1689e1833e1fSj_mayer                 default:
1690e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
1691e1833e1fSj_mayer                               env->error_code);
1692e1833e1fSj_mayer                     break;
1693e1833e1fSj_mayer                 }
1694e1833e1fSj_mayer                 break;
1695e1833e1fSj_mayer             case POWERPC_EXCP_INVAL:
1696e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid instruction\n");
1697e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1698e1833e1fSj_mayer                 info.si_errno = 0;
1699e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1700e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_INVAL:
1701e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPC;
1702e1833e1fSj_mayer                     break;
1703e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_LSWX:
1704e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPN;
1705e1833e1fSj_mayer                     break;
1706e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_SPR:
1707e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1708e1833e1fSj_mayer                     break;
1709e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_FP:
1710e1833e1fSj_mayer                     info.si_code = TARGET_ILL_COPROC;
1711e1833e1fSj_mayer                     break;
1712e1833e1fSj_mayer                 default:
1713e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
1714e1833e1fSj_mayer                               env->error_code & 0xF);
1715e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLADR;
1716e1833e1fSj_mayer                     break;
1717e1833e1fSj_mayer                 }
1718e1833e1fSj_mayer                 break;
1719e1833e1fSj_mayer             case POWERPC_EXCP_PRIV:
1720e1833e1fSj_mayer                 EXCP_DUMP(env, "Privilege violation\n");
1721e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1722e1833e1fSj_mayer                 info.si_errno = 0;
1723e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1724e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_OPC:
1725e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1726e1833e1fSj_mayer                     break;
1727e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_REG:
1728e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1729e1833e1fSj_mayer                     break;
1730e1833e1fSj_mayer                 default:
1731e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
1732e1833e1fSj_mayer                               env->error_code & 0xF);
1733e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1734e1833e1fSj_mayer                     break;
1735e1833e1fSj_mayer                 }
1736e1833e1fSj_mayer                 break;
1737e1833e1fSj_mayer             case POWERPC_EXCP_TRAP:
1738a47dddd7SAndreas Färber                 cpu_abort(cs, "Tried to call a TRAP\n");
1739e1833e1fSj_mayer                 break;
1740e1833e1fSj_mayer             default:
1741e1833e1fSj_mayer                 /* Should not happen ! */
1742a47dddd7SAndreas Färber                 cpu_abort(cs, "Unknown program exception (%02x)\n",
1743e1833e1fSj_mayer                           env->error_code);
1744e1833e1fSj_mayer                 break;
1745e1833e1fSj_mayer             }
1746e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1747624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1748e1833e1fSj_mayer             break;
1749e1833e1fSj_mayer         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
1750e1833e1fSj_mayer             EXCP_DUMP(env, "No floating point allowed\n");
1751e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1752e1833e1fSj_mayer             info.si_errno = 0;
1753e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1754e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1755624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1756e1833e1fSj_mayer             break;
1757e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
1758a47dddd7SAndreas Färber             cpu_abort(cs, "Syscall exception while in user mode. "
1759e1833e1fSj_mayer                       "Aborting\n");
1760e1833e1fSj_mayer             break;
1761e1833e1fSj_mayer         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
1762e1833e1fSj_mayer             EXCP_DUMP(env, "No APU instruction allowed\n");
1763e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1764e1833e1fSj_mayer             info.si_errno = 0;
1765e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1766e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1767624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1768e1833e1fSj_mayer             break;
1769e1833e1fSj_mayer         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
1770a47dddd7SAndreas Färber             cpu_abort(cs, "Decrementer interrupt while in user mode. "
1771e1833e1fSj_mayer                       "Aborting\n");
1772e1833e1fSj_mayer             break;
1773e1833e1fSj_mayer         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
1774a47dddd7SAndreas Färber             cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
1775e1833e1fSj_mayer                       "Aborting\n");
1776e1833e1fSj_mayer             break;
1777e1833e1fSj_mayer         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
1778a47dddd7SAndreas Färber             cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
1779e1833e1fSj_mayer                       "Aborting\n");
1780e1833e1fSj_mayer             break;
1781e1833e1fSj_mayer         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
1782a47dddd7SAndreas Färber             cpu_abort(cs, "Data TLB exception while in user mode. "
1783e1833e1fSj_mayer                       "Aborting\n");
1784e1833e1fSj_mayer             break;
1785e1833e1fSj_mayer         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
1786a47dddd7SAndreas Färber             cpu_abort(cs, "Instruction TLB exception while in user mode. "
1787e1833e1fSj_mayer                       "Aborting\n");
1788e1833e1fSj_mayer             break;
1789e1833e1fSj_mayer         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
1790e1833e1fSj_mayer             EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
1791e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1792e1833e1fSj_mayer             info.si_errno = 0;
1793e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1794e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1795624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1796e1833e1fSj_mayer             break;
1797e1833e1fSj_mayer         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
1798a47dddd7SAndreas Färber             cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
1799e1833e1fSj_mayer             break;
1800e1833e1fSj_mayer         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
1801a47dddd7SAndreas Färber             cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
1802e1833e1fSj_mayer             break;
1803e1833e1fSj_mayer         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
1804a47dddd7SAndreas Färber             cpu_abort(cs, "Performance monitor exception not handled\n");
1805e1833e1fSj_mayer             break;
1806e1833e1fSj_mayer         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
1807a47dddd7SAndreas Färber             cpu_abort(cs, "Doorbell interrupt while in user mode. "
1808e1833e1fSj_mayer                        "Aborting\n");
1809e1833e1fSj_mayer             break;
1810e1833e1fSj_mayer         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
1811a47dddd7SAndreas Färber             cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
1812e1833e1fSj_mayer                       "Aborting\n");
1813e1833e1fSj_mayer             break;
1814e1833e1fSj_mayer         case POWERPC_EXCP_RESET:    /* System reset exception                */
1815a47dddd7SAndreas Färber             cpu_abort(cs, "Reset interrupt while in user mode. "
1816e1833e1fSj_mayer                       "Aborting\n");
1817e1833e1fSj_mayer             break;
1818e1833e1fSj_mayer         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
1819a47dddd7SAndreas Färber             cpu_abort(cs, "Data segment exception while in user mode. "
1820e1833e1fSj_mayer                       "Aborting\n");
1821e1833e1fSj_mayer             break;
1822e1833e1fSj_mayer         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
1823a47dddd7SAndreas Färber             cpu_abort(cs, "Instruction segment exception "
1824e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1825e1833e1fSj_mayer             break;
1826e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1827e1833e1fSj_mayer         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
1828a47dddd7SAndreas Färber             cpu_abort(cs, "Hypervisor decrementer interrupt "
1829e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1830e1833e1fSj_mayer             break;
1831e1833e1fSj_mayer         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
1832e1833e1fSj_mayer             /* Nothing to do:
1833e1833e1fSj_mayer              * we use this exception to emulate step-by-step execution mode.
1834e1833e1fSj_mayer              */
1835e1833e1fSj_mayer             break;
1836e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1837e1833e1fSj_mayer         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
1838a47dddd7SAndreas Färber             cpu_abort(cs, "Hypervisor data storage exception "
1839e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1840e1833e1fSj_mayer             break;
1841e1833e1fSj_mayer         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
1842a47dddd7SAndreas Färber             cpu_abort(cs, "Hypervisor instruction storage exception "
1843e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1844e1833e1fSj_mayer             break;
1845e1833e1fSj_mayer         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
1846a47dddd7SAndreas Färber             cpu_abort(cs, "Hypervisor data segment exception "
1847e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1848e1833e1fSj_mayer             break;
1849e1833e1fSj_mayer         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
1850a47dddd7SAndreas Färber             cpu_abort(cs, "Hypervisor instruction segment exception "
1851e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1852e1833e1fSj_mayer             break;
1853e1833e1fSj_mayer         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
1854e1833e1fSj_mayer             EXCP_DUMP(env, "No Altivec instructions allowed\n");
1855e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1856e1833e1fSj_mayer             info.si_errno = 0;
1857e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1858e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1859624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1860e1833e1fSj_mayer             break;
1861e1833e1fSj_mayer         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
1862a47dddd7SAndreas Färber             cpu_abort(cs, "Programmable interval timer interrupt "
1863e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1864e1833e1fSj_mayer             break;
1865e1833e1fSj_mayer         case POWERPC_EXCP_IO:       /* IO error exception                    */
1866a47dddd7SAndreas Färber             cpu_abort(cs, "IO error exception while in user mode. "
1867e1833e1fSj_mayer                       "Aborting\n");
1868e1833e1fSj_mayer             break;
1869e1833e1fSj_mayer         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
1870a47dddd7SAndreas Färber             cpu_abort(cs, "Run mode exception while in user mode. "
1871e1833e1fSj_mayer                       "Aborting\n");
1872e1833e1fSj_mayer             break;
1873e1833e1fSj_mayer         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
1874a47dddd7SAndreas Färber             cpu_abort(cs, "Emulation trap exception not handled\n");
1875e1833e1fSj_mayer             break;
1876e1833e1fSj_mayer         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
1877a47dddd7SAndreas Färber             cpu_abort(cs, "Instruction fetch TLB exception "
1878e1833e1fSj_mayer                       "while in user-mode. Aborting");
1879e1833e1fSj_mayer             break;
1880e1833e1fSj_mayer         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
1881a47dddd7SAndreas Färber             cpu_abort(cs, "Data load TLB exception while in user-mode. "
1882e1833e1fSj_mayer                       "Aborting");
1883e1833e1fSj_mayer             break;
1884e1833e1fSj_mayer         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
1885a47dddd7SAndreas Färber             cpu_abort(cs, "Data store TLB exception while in user-mode. "
1886e1833e1fSj_mayer                       "Aborting");
1887e1833e1fSj_mayer             break;
1888e1833e1fSj_mayer         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
1889a47dddd7SAndreas Färber             cpu_abort(cs, "Floating-point assist exception not handled\n");
1890e1833e1fSj_mayer             break;
1891e1833e1fSj_mayer         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
1892a47dddd7SAndreas Färber             cpu_abort(cs, "Instruction address breakpoint exception "
1893e1833e1fSj_mayer                       "not handled\n");
1894e1833e1fSj_mayer             break;
1895e1833e1fSj_mayer         case POWERPC_EXCP_SMI:      /* System management interrupt           */
1896a47dddd7SAndreas Färber             cpu_abort(cs, "System management interrupt while in user mode. "
1897e1833e1fSj_mayer                       "Aborting\n");
1898e1833e1fSj_mayer             break;
1899e1833e1fSj_mayer         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
1900a47dddd7SAndreas Färber             cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
1901e1833e1fSj_mayer                       "Aborting\n");
1902e1833e1fSj_mayer             break;
1903e1833e1fSj_mayer         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
1904a47dddd7SAndreas Färber             cpu_abort(cs, "Performance monitor exception not handled\n");
1905e1833e1fSj_mayer             break;
1906e1833e1fSj_mayer         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
1907a47dddd7SAndreas Färber             cpu_abort(cs, "Vector assist exception not handled\n");
1908e1833e1fSj_mayer             break;
1909e1833e1fSj_mayer         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
1910a47dddd7SAndreas Färber             cpu_abort(cs, "Soft patch exception not handled\n");
1911e1833e1fSj_mayer             break;
1912e1833e1fSj_mayer         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
1913a47dddd7SAndreas Färber             cpu_abort(cs, "Maintenance exception while in user mode. "
1914e1833e1fSj_mayer                       "Aborting\n");
1915e1833e1fSj_mayer             break;
1916e1833e1fSj_mayer         case POWERPC_EXCP_STOP:     /* stop translation                      */
1917e1833e1fSj_mayer             /* We did invalidate the instruction cache. Go on */
1918e1833e1fSj_mayer             break;
1919e1833e1fSj_mayer         case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
1920e1833e1fSj_mayer             /* We just stopped because of a branch. Go on */
1921e1833e1fSj_mayer             break;
1922e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL_USER:
1923e1833e1fSj_mayer             /* system call in user-mode emulation */
192467867308Sbellard             /* WARNING:
192567867308Sbellard              * PPC ABI uses overflow flag in cr0 to signal an error
192667867308Sbellard              * in syscalls.
192767867308Sbellard              */
192867867308Sbellard             env->crf[0] &= ~0x1;
192967867308Sbellard             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
193067867308Sbellard                              env->gpr[5], env->gpr[6], env->gpr[7],
19315945cfcbSPeter Maydell                              env->gpr[8], 0, 0);
19329e0e2f96SRichard Henderson             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
1933bcd4933aSNathan Froyd                 /* Returning from a successful sigreturn syscall.
1934bcd4933aSNathan Froyd                    Avoid corrupting register state.  */
1935bcd4933aSNathan Froyd                 break;
1936bcd4933aSNathan Froyd             }
19379e0e2f96SRichard Henderson             if (ret > (target_ulong)(-515)) {
193867867308Sbellard                 env->crf[0] |= 0x1;
193967867308Sbellard                 ret = -ret;
194067867308Sbellard             }
194167867308Sbellard             env->gpr[3] = ret;
194261190b14Sbellard             break;
194356f066bbSNathan Froyd         case POWERPC_EXCP_STCX:
194456f066bbSNathan Froyd             if (do_store_exclusive(env)) {
194556f066bbSNathan Froyd                 info.si_signo = TARGET_SIGSEGV;
194656f066bbSNathan Froyd                 info.si_errno = 0;
194756f066bbSNathan Froyd                 info.si_code = TARGET_SEGV_MAPERR;
194856f066bbSNathan Froyd                 info._sifields._sigfault._addr = env->nip;
194956f066bbSNathan Froyd                 queue_signal(env, info.si_signo, &info);
195056f066bbSNathan Froyd             }
195156f066bbSNathan Froyd             break;
195271f75756Saurel32         case EXCP_DEBUG:
195371f75756Saurel32             {
195471f75756Saurel32                 int sig;
195571f75756Saurel32 
1956db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
195771f75756Saurel32                 if (sig) {
195871f75756Saurel32                     info.si_signo = sig;
195971f75756Saurel32                     info.si_errno = 0;
196071f75756Saurel32                     info.si_code = TARGET_TRAP_BRKPT;
196171f75756Saurel32                     queue_signal(env, info.si_signo, &info);
196271f75756Saurel32                   }
196371f75756Saurel32             }
196471f75756Saurel32             break;
196556ba31ffSj_mayer         case EXCP_INTERRUPT:
196656ba31ffSj_mayer             /* just indicate that signals should be handled asap */
196756ba31ffSj_mayer             break;
196861190b14Sbellard         default:
1969a47dddd7SAndreas Färber             cpu_abort(cs, "Unknown exception 0x%d. Aborting\n", trapnr);
197067867308Sbellard             break;
197167867308Sbellard         }
197267867308Sbellard         process_pending_signals(env);
197367867308Sbellard     }
197467867308Sbellard }
197567867308Sbellard #endif
197667867308Sbellard 
1977048f6b4dSbellard #ifdef TARGET_MIPS
1978048f6b4dSbellard 
1979ff4f7382SRichard Henderson # ifdef TARGET_ABI_MIPSO32
1980048f6b4dSbellard #  define MIPS_SYS(name, args) args,
1981048f6b4dSbellard static const uint8_t mips_syscall_args[] = {
198229fb0f25SAn-Cheng Huang 	MIPS_SYS(sys_syscall	, 8)	/* 4000 */
1983048f6b4dSbellard 	MIPS_SYS(sys_exit	, 1)
1984048f6b4dSbellard 	MIPS_SYS(sys_fork	, 0)
1985048f6b4dSbellard 	MIPS_SYS(sys_read	, 3)
1986048f6b4dSbellard 	MIPS_SYS(sys_write	, 3)
1987048f6b4dSbellard 	MIPS_SYS(sys_open	, 3)	/* 4005 */
1988048f6b4dSbellard 	MIPS_SYS(sys_close	, 1)
1989048f6b4dSbellard 	MIPS_SYS(sys_waitpid	, 3)
1990048f6b4dSbellard 	MIPS_SYS(sys_creat	, 2)
1991048f6b4dSbellard 	MIPS_SYS(sys_link	, 2)
1992048f6b4dSbellard 	MIPS_SYS(sys_unlink	, 1)	/* 4010 */
1993048f6b4dSbellard 	MIPS_SYS(sys_execve	, 0)
1994048f6b4dSbellard 	MIPS_SYS(sys_chdir	, 1)
1995048f6b4dSbellard 	MIPS_SYS(sys_time	, 1)
1996048f6b4dSbellard 	MIPS_SYS(sys_mknod	, 3)
1997048f6b4dSbellard 	MIPS_SYS(sys_chmod	, 2)	/* 4015 */
1998048f6b4dSbellard 	MIPS_SYS(sys_lchown	, 3)
1999048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2000048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_stat */
2001048f6b4dSbellard 	MIPS_SYS(sys_lseek	, 3)
2002048f6b4dSbellard 	MIPS_SYS(sys_getpid	, 0)	/* 4020 */
2003048f6b4dSbellard 	MIPS_SYS(sys_mount	, 5)
2004868e34d7SRichard Henderson 	MIPS_SYS(sys_umount	, 1)
2005048f6b4dSbellard 	MIPS_SYS(sys_setuid	, 1)
2006048f6b4dSbellard 	MIPS_SYS(sys_getuid	, 0)
2007048f6b4dSbellard 	MIPS_SYS(sys_stime	, 1)	/* 4025 */
2008048f6b4dSbellard 	MIPS_SYS(sys_ptrace	, 4)
2009048f6b4dSbellard 	MIPS_SYS(sys_alarm	, 1)
2010048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_fstat */
2011048f6b4dSbellard 	MIPS_SYS(sys_pause	, 0)
2012048f6b4dSbellard 	MIPS_SYS(sys_utime	, 2)	/* 4030 */
2013048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2014048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2015048f6b4dSbellard 	MIPS_SYS(sys_access	, 2)
2016048f6b4dSbellard 	MIPS_SYS(sys_nice	, 1)
2017048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4035 */
2018048f6b4dSbellard 	MIPS_SYS(sys_sync	, 0)
2019048f6b4dSbellard 	MIPS_SYS(sys_kill	, 2)
2020048f6b4dSbellard 	MIPS_SYS(sys_rename	, 2)
2021048f6b4dSbellard 	MIPS_SYS(sys_mkdir	, 2)
2022048f6b4dSbellard 	MIPS_SYS(sys_rmdir	, 1)	/* 4040 */
2023048f6b4dSbellard 	MIPS_SYS(sys_dup		, 1)
2024048f6b4dSbellard 	MIPS_SYS(sys_pipe	, 0)
2025048f6b4dSbellard 	MIPS_SYS(sys_times	, 1)
2026048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2027048f6b4dSbellard 	MIPS_SYS(sys_brk		, 1)	/* 4045 */
2028048f6b4dSbellard 	MIPS_SYS(sys_setgid	, 1)
2029048f6b4dSbellard 	MIPS_SYS(sys_getgid	, 0)
2030048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was signal(2) */
2031048f6b4dSbellard 	MIPS_SYS(sys_geteuid	, 0)
2032048f6b4dSbellard 	MIPS_SYS(sys_getegid	, 0)	/* 4050 */
2033048f6b4dSbellard 	MIPS_SYS(sys_acct	, 0)
2034868e34d7SRichard Henderson 	MIPS_SYS(sys_umount2	, 2)
2035048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2036048f6b4dSbellard 	MIPS_SYS(sys_ioctl	, 3)
2037048f6b4dSbellard 	MIPS_SYS(sys_fcntl	, 3)	/* 4055 */
2038048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 2)
2039048f6b4dSbellard 	MIPS_SYS(sys_setpgid	, 2)
2040048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2041048f6b4dSbellard 	MIPS_SYS(sys_olduname	, 1)
2042048f6b4dSbellard 	MIPS_SYS(sys_umask	, 1)	/* 4060 */
2043048f6b4dSbellard 	MIPS_SYS(sys_chroot	, 1)
2044048f6b4dSbellard 	MIPS_SYS(sys_ustat	, 2)
2045048f6b4dSbellard 	MIPS_SYS(sys_dup2	, 2)
2046048f6b4dSbellard 	MIPS_SYS(sys_getppid	, 0)
2047048f6b4dSbellard 	MIPS_SYS(sys_getpgrp	, 0)	/* 4065 */
2048048f6b4dSbellard 	MIPS_SYS(sys_setsid	, 0)
2049048f6b4dSbellard 	MIPS_SYS(sys_sigaction	, 3)
2050048f6b4dSbellard 	MIPS_SYS(sys_sgetmask	, 0)
2051048f6b4dSbellard 	MIPS_SYS(sys_ssetmask	, 1)
2052048f6b4dSbellard 	MIPS_SYS(sys_setreuid	, 2)	/* 4070 */
2053048f6b4dSbellard 	MIPS_SYS(sys_setregid	, 2)
2054048f6b4dSbellard 	MIPS_SYS(sys_sigsuspend	, 0)
2055048f6b4dSbellard 	MIPS_SYS(sys_sigpending	, 1)
2056048f6b4dSbellard 	MIPS_SYS(sys_sethostname	, 2)
2057048f6b4dSbellard 	MIPS_SYS(sys_setrlimit	, 2)	/* 4075 */
2058048f6b4dSbellard 	MIPS_SYS(sys_getrlimit	, 2)
2059048f6b4dSbellard 	MIPS_SYS(sys_getrusage	, 2)
2060048f6b4dSbellard 	MIPS_SYS(sys_gettimeofday, 2)
2061048f6b4dSbellard 	MIPS_SYS(sys_settimeofday, 2)
2062048f6b4dSbellard 	MIPS_SYS(sys_getgroups	, 2)	/* 4080 */
2063048f6b4dSbellard 	MIPS_SYS(sys_setgroups	, 2)
2064048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* old_select */
2065048f6b4dSbellard 	MIPS_SYS(sys_symlink	, 2)
2066048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_lstat */
2067048f6b4dSbellard 	MIPS_SYS(sys_readlink	, 3)	/* 4085 */
2068048f6b4dSbellard 	MIPS_SYS(sys_uselib	, 1)
2069048f6b4dSbellard 	MIPS_SYS(sys_swapon	, 2)
2070048f6b4dSbellard 	MIPS_SYS(sys_reboot	, 3)
2071048f6b4dSbellard 	MIPS_SYS(old_readdir	, 3)
2072048f6b4dSbellard 	MIPS_SYS(old_mmap	, 6)	/* 4090 */
2073048f6b4dSbellard 	MIPS_SYS(sys_munmap	, 2)
2074048f6b4dSbellard 	MIPS_SYS(sys_truncate	, 2)
2075048f6b4dSbellard 	MIPS_SYS(sys_ftruncate	, 2)
2076048f6b4dSbellard 	MIPS_SYS(sys_fchmod	, 2)
2077048f6b4dSbellard 	MIPS_SYS(sys_fchown	, 3)	/* 4095 */
2078048f6b4dSbellard 	MIPS_SYS(sys_getpriority	, 2)
2079048f6b4dSbellard 	MIPS_SYS(sys_setpriority	, 3)
2080048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2081048f6b4dSbellard 	MIPS_SYS(sys_statfs	, 2)
2082048f6b4dSbellard 	MIPS_SYS(sys_fstatfs	, 2)	/* 4100 */
2083048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was ioperm(2) */
2084048f6b4dSbellard 	MIPS_SYS(sys_socketcall	, 2)
2085048f6b4dSbellard 	MIPS_SYS(sys_syslog	, 3)
2086048f6b4dSbellard 	MIPS_SYS(sys_setitimer	, 3)
2087048f6b4dSbellard 	MIPS_SYS(sys_getitimer	, 2)	/* 4105 */
2088048f6b4dSbellard 	MIPS_SYS(sys_newstat	, 2)
2089048f6b4dSbellard 	MIPS_SYS(sys_newlstat	, 2)
2090048f6b4dSbellard 	MIPS_SYS(sys_newfstat	, 2)
2091048f6b4dSbellard 	MIPS_SYS(sys_uname	, 1)
2092048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4110 was iopl(2) */
2093048f6b4dSbellard 	MIPS_SYS(sys_vhangup	, 0)
2094048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_idle() */
2095048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_vm86 */
2096048f6b4dSbellard 	MIPS_SYS(sys_wait4	, 4)
2097048f6b4dSbellard 	MIPS_SYS(sys_swapoff	, 1)	/* 4115 */
2098048f6b4dSbellard 	MIPS_SYS(sys_sysinfo	, 1)
2099048f6b4dSbellard 	MIPS_SYS(sys_ipc		, 6)
2100048f6b4dSbellard 	MIPS_SYS(sys_fsync	, 1)
2101048f6b4dSbellard 	MIPS_SYS(sys_sigreturn	, 0)
210218113962SPaul Brook 	MIPS_SYS(sys_clone	, 6)	/* 4120 */
2103048f6b4dSbellard 	MIPS_SYS(sys_setdomainname, 2)
2104048f6b4dSbellard 	MIPS_SYS(sys_newuname	, 1)
2105048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_modify_ldt */
2106048f6b4dSbellard 	MIPS_SYS(sys_adjtimex	, 1)
2107048f6b4dSbellard 	MIPS_SYS(sys_mprotect	, 3)	/* 4125 */
2108048f6b4dSbellard 	MIPS_SYS(sys_sigprocmask	, 3)
2109048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was create_module */
2110048f6b4dSbellard 	MIPS_SYS(sys_init_module	, 5)
2111048f6b4dSbellard 	MIPS_SYS(sys_delete_module, 1)
2112048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4130	was get_kernel_syms */
2113048f6b4dSbellard 	MIPS_SYS(sys_quotactl	, 0)
2114048f6b4dSbellard 	MIPS_SYS(sys_getpgid	, 1)
2115048f6b4dSbellard 	MIPS_SYS(sys_fchdir	, 1)
2116048f6b4dSbellard 	MIPS_SYS(sys_bdflush	, 2)
2117048f6b4dSbellard 	MIPS_SYS(sys_sysfs	, 3)	/* 4135 */
2118048f6b4dSbellard 	MIPS_SYS(sys_personality	, 1)
2119048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* for afs_syscall */
2120048f6b4dSbellard 	MIPS_SYS(sys_setfsuid	, 1)
2121048f6b4dSbellard 	MIPS_SYS(sys_setfsgid	, 1)
2122048f6b4dSbellard 	MIPS_SYS(sys_llseek	, 5)	/* 4140 */
2123048f6b4dSbellard 	MIPS_SYS(sys_getdents	, 3)
2124048f6b4dSbellard 	MIPS_SYS(sys_select	, 5)
2125048f6b4dSbellard 	MIPS_SYS(sys_flock	, 2)
2126048f6b4dSbellard 	MIPS_SYS(sys_msync	, 3)
2127048f6b4dSbellard 	MIPS_SYS(sys_readv	, 3)	/* 4145 */
2128048f6b4dSbellard 	MIPS_SYS(sys_writev	, 3)
2129048f6b4dSbellard 	MIPS_SYS(sys_cacheflush	, 3)
2130048f6b4dSbellard 	MIPS_SYS(sys_cachectl	, 3)
2131048f6b4dSbellard 	MIPS_SYS(sys_sysmips	, 4)
2132048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4150 */
2133048f6b4dSbellard 	MIPS_SYS(sys_getsid	, 1)
2134048f6b4dSbellard 	MIPS_SYS(sys_fdatasync	, 0)
2135048f6b4dSbellard 	MIPS_SYS(sys_sysctl	, 1)
2136048f6b4dSbellard 	MIPS_SYS(sys_mlock	, 2)
2137048f6b4dSbellard 	MIPS_SYS(sys_munlock	, 2)	/* 4155 */
2138048f6b4dSbellard 	MIPS_SYS(sys_mlockall	, 1)
2139048f6b4dSbellard 	MIPS_SYS(sys_munlockall	, 0)
2140048f6b4dSbellard 	MIPS_SYS(sys_sched_setparam, 2)
2141048f6b4dSbellard 	MIPS_SYS(sys_sched_getparam, 2)
2142048f6b4dSbellard 	MIPS_SYS(sys_sched_setscheduler, 3)	/* 4160 */
2143048f6b4dSbellard 	MIPS_SYS(sys_sched_getscheduler, 1)
2144048f6b4dSbellard 	MIPS_SYS(sys_sched_yield	, 0)
2145048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_max, 1)
2146048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_min, 1)
2147048f6b4dSbellard 	MIPS_SYS(sys_sched_rr_get_interval, 2)	/* 4165 */
2148048f6b4dSbellard 	MIPS_SYS(sys_nanosleep,	2)
2149b0932e06SPetar Jovanovic 	MIPS_SYS(sys_mremap	, 5)
2150048f6b4dSbellard 	MIPS_SYS(sys_accept	, 3)
2151048f6b4dSbellard 	MIPS_SYS(sys_bind	, 3)
2152048f6b4dSbellard 	MIPS_SYS(sys_connect	, 3)	/* 4170 */
2153048f6b4dSbellard 	MIPS_SYS(sys_getpeername	, 3)
2154048f6b4dSbellard 	MIPS_SYS(sys_getsockname	, 3)
2155048f6b4dSbellard 	MIPS_SYS(sys_getsockopt	, 5)
2156048f6b4dSbellard 	MIPS_SYS(sys_listen	, 2)
2157048f6b4dSbellard 	MIPS_SYS(sys_recv	, 4)	/* 4175 */
2158048f6b4dSbellard 	MIPS_SYS(sys_recvfrom	, 6)
2159048f6b4dSbellard 	MIPS_SYS(sys_recvmsg	, 3)
2160048f6b4dSbellard 	MIPS_SYS(sys_send	, 4)
2161048f6b4dSbellard 	MIPS_SYS(sys_sendmsg	, 3)
2162048f6b4dSbellard 	MIPS_SYS(sys_sendto	, 6)	/* 4180 */
2163048f6b4dSbellard 	MIPS_SYS(sys_setsockopt	, 5)
2164048f6b4dSbellard 	MIPS_SYS(sys_shutdown	, 2)
2165048f6b4dSbellard 	MIPS_SYS(sys_socket	, 3)
2166048f6b4dSbellard 	MIPS_SYS(sys_socketpair	, 4)
2167048f6b4dSbellard 	MIPS_SYS(sys_setresuid	, 3)	/* 4185 */
2168048f6b4dSbellard 	MIPS_SYS(sys_getresuid	, 3)
2169048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_query_module */
2170048f6b4dSbellard 	MIPS_SYS(sys_poll	, 3)
2171048f6b4dSbellard 	MIPS_SYS(sys_nfsservctl	, 3)
2172048f6b4dSbellard 	MIPS_SYS(sys_setresgid	, 3)	/* 4190 */
2173048f6b4dSbellard 	MIPS_SYS(sys_getresgid	, 3)
2174048f6b4dSbellard 	MIPS_SYS(sys_prctl	, 5)
2175048f6b4dSbellard 	MIPS_SYS(sys_rt_sigreturn, 0)
2176048f6b4dSbellard 	MIPS_SYS(sys_rt_sigaction, 4)
2177048f6b4dSbellard 	MIPS_SYS(sys_rt_sigprocmask, 4)	/* 4195 */
2178048f6b4dSbellard 	MIPS_SYS(sys_rt_sigpending, 2)
2179048f6b4dSbellard 	MIPS_SYS(sys_rt_sigtimedwait, 4)
2180048f6b4dSbellard 	MIPS_SYS(sys_rt_sigqueueinfo, 3)
2181048f6b4dSbellard 	MIPS_SYS(sys_rt_sigsuspend, 0)
2182048f6b4dSbellard 	MIPS_SYS(sys_pread64	, 6)	/* 4200 */
2183048f6b4dSbellard 	MIPS_SYS(sys_pwrite64	, 6)
2184048f6b4dSbellard 	MIPS_SYS(sys_chown	, 3)
2185048f6b4dSbellard 	MIPS_SYS(sys_getcwd	, 2)
2186048f6b4dSbellard 	MIPS_SYS(sys_capget	, 2)
2187048f6b4dSbellard 	MIPS_SYS(sys_capset	, 2)	/* 4205 */
2188053ebb27SWesley W. Terpstra 	MIPS_SYS(sys_sigaltstack	, 2)
2189048f6b4dSbellard 	MIPS_SYS(sys_sendfile	, 4)
2190048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2191048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2192048f6b4dSbellard 	MIPS_SYS(sys_mmap2	, 6)	/* 4210 */
2193048f6b4dSbellard 	MIPS_SYS(sys_truncate64	, 4)
2194048f6b4dSbellard 	MIPS_SYS(sys_ftruncate64	, 4)
2195048f6b4dSbellard 	MIPS_SYS(sys_stat64	, 2)
2196048f6b4dSbellard 	MIPS_SYS(sys_lstat64	, 2)
2197048f6b4dSbellard 	MIPS_SYS(sys_fstat64	, 2)	/* 4215 */
2198048f6b4dSbellard 	MIPS_SYS(sys_pivot_root	, 2)
2199048f6b4dSbellard 	MIPS_SYS(sys_mincore	, 3)
2200048f6b4dSbellard 	MIPS_SYS(sys_madvise	, 3)
2201048f6b4dSbellard 	MIPS_SYS(sys_getdents64	, 3)
2202048f6b4dSbellard 	MIPS_SYS(sys_fcntl64	, 3)	/* 4220 */
2203048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2204048f6b4dSbellard 	MIPS_SYS(sys_gettid	, 0)
2205048f6b4dSbellard 	MIPS_SYS(sys_readahead	, 5)
2206048f6b4dSbellard 	MIPS_SYS(sys_setxattr	, 5)
2207048f6b4dSbellard 	MIPS_SYS(sys_lsetxattr	, 5)	/* 4225 */
2208048f6b4dSbellard 	MIPS_SYS(sys_fsetxattr	, 5)
2209048f6b4dSbellard 	MIPS_SYS(sys_getxattr	, 4)
2210048f6b4dSbellard 	MIPS_SYS(sys_lgetxattr	, 4)
2211048f6b4dSbellard 	MIPS_SYS(sys_fgetxattr	, 4)
2212048f6b4dSbellard 	MIPS_SYS(sys_listxattr	, 3)	/* 4230 */
2213048f6b4dSbellard 	MIPS_SYS(sys_llistxattr	, 3)
2214048f6b4dSbellard 	MIPS_SYS(sys_flistxattr	, 3)
2215048f6b4dSbellard 	MIPS_SYS(sys_removexattr	, 2)
2216048f6b4dSbellard 	MIPS_SYS(sys_lremovexattr, 2)
2217048f6b4dSbellard 	MIPS_SYS(sys_fremovexattr, 2)	/* 4235 */
2218048f6b4dSbellard 	MIPS_SYS(sys_tkill	, 2)
2219048f6b4dSbellard 	MIPS_SYS(sys_sendfile64	, 5)
222043be1343SPetar Jovanovic 	MIPS_SYS(sys_futex	, 6)
2221048f6b4dSbellard 	MIPS_SYS(sys_sched_setaffinity, 3)
2222048f6b4dSbellard 	MIPS_SYS(sys_sched_getaffinity, 3)	/* 4240 */
2223048f6b4dSbellard 	MIPS_SYS(sys_io_setup	, 2)
2224048f6b4dSbellard 	MIPS_SYS(sys_io_destroy	, 1)
2225048f6b4dSbellard 	MIPS_SYS(sys_io_getevents, 5)
2226048f6b4dSbellard 	MIPS_SYS(sys_io_submit	, 3)
2227048f6b4dSbellard 	MIPS_SYS(sys_io_cancel	, 3)	/* 4245 */
2228048f6b4dSbellard 	MIPS_SYS(sys_exit_group	, 1)
2229048f6b4dSbellard 	MIPS_SYS(sys_lookup_dcookie, 3)
2230048f6b4dSbellard 	MIPS_SYS(sys_epoll_create, 1)
2231048f6b4dSbellard 	MIPS_SYS(sys_epoll_ctl	, 4)
2232048f6b4dSbellard 	MIPS_SYS(sys_epoll_wait	, 3)	/* 4250 */
2233048f6b4dSbellard 	MIPS_SYS(sys_remap_file_pages, 5)
2234048f6b4dSbellard 	MIPS_SYS(sys_set_tid_address, 1)
2235048f6b4dSbellard 	MIPS_SYS(sys_restart_syscall, 0)
2236048f6b4dSbellard 	MIPS_SYS(sys_fadvise64_64, 7)
2237048f6b4dSbellard 	MIPS_SYS(sys_statfs64	, 3)	/* 4255 */
2238048f6b4dSbellard 	MIPS_SYS(sys_fstatfs64	, 2)
2239048f6b4dSbellard 	MIPS_SYS(sys_timer_create, 3)
2240048f6b4dSbellard 	MIPS_SYS(sys_timer_settime, 4)
2241048f6b4dSbellard 	MIPS_SYS(sys_timer_gettime, 2)
2242048f6b4dSbellard 	MIPS_SYS(sys_timer_getoverrun, 1)	/* 4260 */
2243048f6b4dSbellard 	MIPS_SYS(sys_timer_delete, 1)
2244048f6b4dSbellard 	MIPS_SYS(sys_clock_settime, 2)
2245048f6b4dSbellard 	MIPS_SYS(sys_clock_gettime, 2)
2246048f6b4dSbellard 	MIPS_SYS(sys_clock_getres, 2)
2247048f6b4dSbellard 	MIPS_SYS(sys_clock_nanosleep, 4)	/* 4265 */
2248048f6b4dSbellard 	MIPS_SYS(sys_tgkill	, 3)
2249048f6b4dSbellard 	MIPS_SYS(sys_utimes	, 2)
2250048f6b4dSbellard 	MIPS_SYS(sys_mbind	, 4)
2251048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_get_mempolicy */
2252048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4270 sys_set_mempolicy */
2253048f6b4dSbellard 	MIPS_SYS(sys_mq_open	, 4)
2254048f6b4dSbellard 	MIPS_SYS(sys_mq_unlink	, 1)
2255048f6b4dSbellard 	MIPS_SYS(sys_mq_timedsend, 5)
2256048f6b4dSbellard 	MIPS_SYS(sys_mq_timedreceive, 5)
2257048f6b4dSbellard 	MIPS_SYS(sys_mq_notify	, 2)	/* 4275 */
2258048f6b4dSbellard 	MIPS_SYS(sys_mq_getsetattr, 3)
2259048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_vserver */
2260048f6b4dSbellard 	MIPS_SYS(sys_waitid	, 4)
2261048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
2262048f6b4dSbellard 	MIPS_SYS(sys_add_key	, 5)
2263048f6b4dSbellard 	MIPS_SYS(sys_request_key, 4)
2264048f6b4dSbellard 	MIPS_SYS(sys_keyctl	, 5)
22656f5b89a0Sths 	MIPS_SYS(sys_set_thread_area, 1)
2266388bb21aSths 	MIPS_SYS(sys_inotify_init, 0)
2267388bb21aSths 	MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
2268388bb21aSths 	MIPS_SYS(sys_inotify_rm_watch, 2)
2269388bb21aSths 	MIPS_SYS(sys_migrate_pages, 4)
2270388bb21aSths 	MIPS_SYS(sys_openat, 4)
2271388bb21aSths 	MIPS_SYS(sys_mkdirat, 3)
2272388bb21aSths 	MIPS_SYS(sys_mknodat, 4)	/* 4290 */
2273388bb21aSths 	MIPS_SYS(sys_fchownat, 5)
2274388bb21aSths 	MIPS_SYS(sys_futimesat, 3)
2275388bb21aSths 	MIPS_SYS(sys_fstatat64, 4)
2276388bb21aSths 	MIPS_SYS(sys_unlinkat, 3)
2277388bb21aSths 	MIPS_SYS(sys_renameat, 4)	/* 4295 */
2278388bb21aSths 	MIPS_SYS(sys_linkat, 5)
2279388bb21aSths 	MIPS_SYS(sys_symlinkat, 3)
2280388bb21aSths 	MIPS_SYS(sys_readlinkat, 4)
2281388bb21aSths 	MIPS_SYS(sys_fchmodat, 3)
2282388bb21aSths 	MIPS_SYS(sys_faccessat, 3)	/* 4300 */
2283388bb21aSths 	MIPS_SYS(sys_pselect6, 6)
2284388bb21aSths 	MIPS_SYS(sys_ppoll, 5)
2285388bb21aSths 	MIPS_SYS(sys_unshare, 1)
2286b0932e06SPetar Jovanovic 	MIPS_SYS(sys_splice, 6)
2287388bb21aSths 	MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
2288388bb21aSths 	MIPS_SYS(sys_tee, 4)
2289388bb21aSths 	MIPS_SYS(sys_vmsplice, 4)
2290388bb21aSths 	MIPS_SYS(sys_move_pages, 6)
2291388bb21aSths 	MIPS_SYS(sys_set_robust_list, 2)
2292388bb21aSths 	MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
2293388bb21aSths 	MIPS_SYS(sys_kexec_load, 4)
2294388bb21aSths 	MIPS_SYS(sys_getcpu, 3)
2295388bb21aSths 	MIPS_SYS(sys_epoll_pwait, 6)
2296388bb21aSths 	MIPS_SYS(sys_ioprio_set, 3)
2297388bb21aSths 	MIPS_SYS(sys_ioprio_get, 2)
2298d979e8ebSPeter Maydell         MIPS_SYS(sys_utimensat, 4)
2299d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd, 3)
2300d979e8ebSPeter Maydell         MIPS_SYS(sys_ni_syscall, 0)     /* was timerfd */
2301d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd, 1)
2302d979e8ebSPeter Maydell         MIPS_SYS(sys_fallocate, 6)      /* 4320 */
2303d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_create, 2)
2304d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_gettime, 2)
2305d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_settime, 4)
2306d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd4, 4)
2307d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd2, 2)       /* 4325 */
2308d979e8ebSPeter Maydell         MIPS_SYS(sys_epoll_create1, 1)
2309d979e8ebSPeter Maydell         MIPS_SYS(sys_dup3, 3)
2310d979e8ebSPeter Maydell         MIPS_SYS(sys_pipe2, 2)
2311d979e8ebSPeter Maydell         MIPS_SYS(sys_inotify_init1, 1)
2312d979e8ebSPeter Maydell         MIPS_SYS(sys_preadv, 6)         /* 4330 */
2313d979e8ebSPeter Maydell         MIPS_SYS(sys_pwritev, 6)
2314d979e8ebSPeter Maydell         MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
2315d979e8ebSPeter Maydell         MIPS_SYS(sys_perf_event_open, 5)
2316d979e8ebSPeter Maydell         MIPS_SYS(sys_accept4, 4)
2317d979e8ebSPeter Maydell         MIPS_SYS(sys_recvmmsg, 5)       /* 4335 */
2318d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_init, 2)
2319d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_mark, 6)
2320d979e8ebSPeter Maydell         MIPS_SYS(sys_prlimit64, 4)
2321d979e8ebSPeter Maydell         MIPS_SYS(sys_name_to_handle_at, 5)
2322d979e8ebSPeter Maydell         MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
2323d979e8ebSPeter Maydell         MIPS_SYS(sys_clock_adjtime, 2)
2324d979e8ebSPeter Maydell         MIPS_SYS(sys_syncfs, 1)
2325048f6b4dSbellard };
2326048f6b4dSbellard #  undef MIPS_SYS
2327ff4f7382SRichard Henderson # endif /* O32 */
2328048f6b4dSbellard 
2329590bc601SPaul Brook static int do_store_exclusive(CPUMIPSState *env)
2330590bc601SPaul Brook {
2331590bc601SPaul Brook     target_ulong addr;
2332590bc601SPaul Brook     target_ulong page_addr;
2333590bc601SPaul Brook     target_ulong val;
2334590bc601SPaul Brook     int flags;
2335590bc601SPaul Brook     int segv = 0;
2336590bc601SPaul Brook     int reg;
2337590bc601SPaul Brook     int d;
2338590bc601SPaul Brook 
23395499b6ffSAurelien Jarno     addr = env->lladdr;
2340590bc601SPaul Brook     page_addr = addr & TARGET_PAGE_MASK;
2341590bc601SPaul Brook     start_exclusive();
2342590bc601SPaul Brook     mmap_lock();
2343590bc601SPaul Brook     flags = page_get_flags(page_addr);
2344590bc601SPaul Brook     if ((flags & PAGE_READ) == 0) {
2345590bc601SPaul Brook         segv = 1;
2346590bc601SPaul Brook     } else {
2347590bc601SPaul Brook         reg = env->llreg & 0x1f;
2348590bc601SPaul Brook         d = (env->llreg & 0x20) != 0;
2349590bc601SPaul Brook         if (d) {
2350590bc601SPaul Brook             segv = get_user_s64(val, addr);
2351590bc601SPaul Brook         } else {
2352590bc601SPaul Brook             segv = get_user_s32(val, addr);
2353590bc601SPaul Brook         }
2354590bc601SPaul Brook         if (!segv) {
2355590bc601SPaul Brook             if (val != env->llval) {
2356590bc601SPaul Brook                 env->active_tc.gpr[reg] = 0;
2357590bc601SPaul Brook             } else {
2358590bc601SPaul Brook                 if (d) {
2359590bc601SPaul Brook                     segv = put_user_u64(env->llnewval, addr);
2360590bc601SPaul Brook                 } else {
2361590bc601SPaul Brook                     segv = put_user_u32(env->llnewval, addr);
2362590bc601SPaul Brook                 }
2363590bc601SPaul Brook                 if (!segv) {
2364590bc601SPaul Brook                     env->active_tc.gpr[reg] = 1;
2365590bc601SPaul Brook                 }
2366590bc601SPaul Brook             }
2367590bc601SPaul Brook         }
2368590bc601SPaul Brook     }
23695499b6ffSAurelien Jarno     env->lladdr = -1;
2370590bc601SPaul Brook     if (!segv) {
2371590bc601SPaul Brook         env->active_tc.PC += 4;
2372590bc601SPaul Brook     }
2373590bc601SPaul Brook     mmap_unlock();
2374590bc601SPaul Brook     end_exclusive();
2375590bc601SPaul Brook     return segv;
2376590bc601SPaul Brook }
2377590bc601SPaul Brook 
237854b2f42cSMeador Inge /* Break codes */
237954b2f42cSMeador Inge enum {
238054b2f42cSMeador Inge     BRK_OVERFLOW = 6,
238154b2f42cSMeador Inge     BRK_DIVZERO = 7
238254b2f42cSMeador Inge };
238354b2f42cSMeador Inge 
238454b2f42cSMeador Inge static int do_break(CPUMIPSState *env, target_siginfo_t *info,
238554b2f42cSMeador Inge                     unsigned int code)
238654b2f42cSMeador Inge {
238754b2f42cSMeador Inge     int ret = -1;
238854b2f42cSMeador Inge 
238954b2f42cSMeador Inge     switch (code) {
239054b2f42cSMeador Inge     case BRK_OVERFLOW:
239154b2f42cSMeador Inge     case BRK_DIVZERO:
239254b2f42cSMeador Inge         info->si_signo = TARGET_SIGFPE;
239354b2f42cSMeador Inge         info->si_errno = 0;
239454b2f42cSMeador Inge         info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV;
239554b2f42cSMeador Inge         queue_signal(env, info->si_signo, &*info);
239654b2f42cSMeador Inge         ret = 0;
239754b2f42cSMeador Inge         break;
239854b2f42cSMeador Inge     default:
2399b51910baSPetar Jovanovic         info->si_signo = TARGET_SIGTRAP;
2400b51910baSPetar Jovanovic         info->si_errno = 0;
2401b51910baSPetar Jovanovic         queue_signal(env, info->si_signo, &*info);
2402b51910baSPetar Jovanovic         ret = 0;
240354b2f42cSMeador Inge         break;
240454b2f42cSMeador Inge     }
240554b2f42cSMeador Inge 
240654b2f42cSMeador Inge     return ret;
240754b2f42cSMeador Inge }
240854b2f42cSMeador Inge 
2409048f6b4dSbellard void cpu_loop(CPUMIPSState *env)
2410048f6b4dSbellard {
24110315c31cSAndreas Färber     CPUState *cs = CPU(mips_env_get_cpu(env));
2412c227f099SAnthony Liguori     target_siginfo_t info;
2413ff4f7382SRichard Henderson     int trapnr;
2414ff4f7382SRichard Henderson     abi_long ret;
2415ff4f7382SRichard Henderson # ifdef TARGET_ABI_MIPSO32
2416048f6b4dSbellard     unsigned int syscall_num;
2417ff4f7382SRichard Henderson # endif
2418048f6b4dSbellard 
2419048f6b4dSbellard     for(;;) {
24200315c31cSAndreas Färber         cpu_exec_start(cs);
2421ea3e9847SPeter Crosthwaite         trapnr = cpu_mips_exec(cs);
24220315c31cSAndreas Färber         cpu_exec_end(cs);
2423048f6b4dSbellard         switch(trapnr) {
2424048f6b4dSbellard         case EXCP_SYSCALL:
2425b5dc7732Sths             env->active_tc.PC += 4;
2426ff4f7382SRichard Henderson # ifdef TARGET_ABI_MIPSO32
2427ff4f7382SRichard Henderson             syscall_num = env->active_tc.gpr[2] - 4000;
2428048f6b4dSbellard             if (syscall_num >= sizeof(mips_syscall_args)) {
24297c2f6157SWesley W. Terpstra                 ret = -TARGET_ENOSYS;
2430048f6b4dSbellard             } else {
2431388bb21aSths                 int nb_args;
2432992f48a0Sblueswir1                 abi_ulong sp_reg;
2433992f48a0Sblueswir1                 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
2434388bb21aSths 
2435048f6b4dSbellard                 nb_args = mips_syscall_args[syscall_num];
2436b5dc7732Sths                 sp_reg = env->active_tc.gpr[29];
2437388bb21aSths                 switch (nb_args) {
2438048f6b4dSbellard                 /* these arguments are taken from the stack */
243994c19610SAn-Cheng Huang                 case 8:
244094c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
244194c19610SAn-Cheng Huang                         goto done_syscall;
244294c19610SAn-Cheng Huang                     }
244394c19610SAn-Cheng Huang                 case 7:
244494c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
244594c19610SAn-Cheng Huang                         goto done_syscall;
244694c19610SAn-Cheng Huang                     }
244794c19610SAn-Cheng Huang                 case 6:
244894c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
244994c19610SAn-Cheng Huang                         goto done_syscall;
245094c19610SAn-Cheng Huang                     }
245194c19610SAn-Cheng Huang                 case 5:
245294c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
245394c19610SAn-Cheng Huang                         goto done_syscall;
245494c19610SAn-Cheng Huang                     }
2455388bb21aSths                 default:
2456388bb21aSths                     break;
2457048f6b4dSbellard                 }
2458b5dc7732Sths                 ret = do_syscall(env, env->active_tc.gpr[2],
2459b5dc7732Sths                                  env->active_tc.gpr[4],
2460b5dc7732Sths                                  env->active_tc.gpr[5],
2461b5dc7732Sths                                  env->active_tc.gpr[6],
2462b5dc7732Sths                                  env->active_tc.gpr[7],
24635945cfcbSPeter Maydell                                  arg5, arg6, arg7, arg8);
2464048f6b4dSbellard             }
246594c19610SAn-Cheng Huang done_syscall:
2466ff4f7382SRichard Henderson # else
2467ff4f7382SRichard Henderson             ret = do_syscall(env, env->active_tc.gpr[2],
2468ff4f7382SRichard Henderson                              env->active_tc.gpr[4], env->active_tc.gpr[5],
2469ff4f7382SRichard Henderson                              env->active_tc.gpr[6], env->active_tc.gpr[7],
2470ff4f7382SRichard Henderson                              env->active_tc.gpr[8], env->active_tc.gpr[9],
2471ff4f7382SRichard Henderson                              env->active_tc.gpr[10], env->active_tc.gpr[11]);
2472ff4f7382SRichard Henderson # endif /* O32 */
24730b1bcb00Spbrook             if (ret == -TARGET_QEMU_ESIGRETURN) {
24740b1bcb00Spbrook                 /* Returning from a successful sigreturn syscall.
24750b1bcb00Spbrook                    Avoid clobbering register state.  */
24760b1bcb00Spbrook                 break;
24770b1bcb00Spbrook             }
2478ff4f7382SRichard Henderson             if ((abi_ulong)ret >= (abi_ulong)-1133) {
2479b5dc7732Sths                 env->active_tc.gpr[7] = 1; /* error flag */
2480048f6b4dSbellard                 ret = -ret;
2481048f6b4dSbellard             } else {
2482b5dc7732Sths                 env->active_tc.gpr[7] = 0; /* error flag */
2483388bb21aSths             }
2484b5dc7732Sths             env->active_tc.gpr[2] = ret;
2485048f6b4dSbellard             break;
2486ca7c2b1bSths         case EXCP_TLBL:
2487ca7c2b1bSths         case EXCP_TLBS:
2488e6e5bd2dSWesley W. Terpstra         case EXCP_AdEL:
2489e6e5bd2dSWesley W. Terpstra         case EXCP_AdES:
2490e4474235Spbrook             info.si_signo = TARGET_SIGSEGV;
2491e4474235Spbrook             info.si_errno = 0;
2492e4474235Spbrook             /* XXX: check env->error_code */
2493e4474235Spbrook             info.si_code = TARGET_SEGV_MAPERR;
2494e4474235Spbrook             info._sifields._sigfault._addr = env->CP0_BadVAddr;
2495e4474235Spbrook             queue_signal(env, info.si_signo, &info);
2496e4474235Spbrook             break;
24976900e84bSbellard         case EXCP_CpU:
2498048f6b4dSbellard         case EXCP_RI:
2499048f6b4dSbellard             info.si_signo = TARGET_SIGILL;
2500048f6b4dSbellard             info.si_errno = 0;
2501048f6b4dSbellard             info.si_code = 0;
2502624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2503048f6b4dSbellard             break;
2504106ec879Sbellard         case EXCP_INTERRUPT:
2505106ec879Sbellard             /* just indicate that signals should be handled asap */
2506106ec879Sbellard             break;
2507d08b2a28Spbrook         case EXCP_DEBUG:
2508d08b2a28Spbrook             {
2509d08b2a28Spbrook                 int sig;
2510d08b2a28Spbrook 
2511db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
2512d08b2a28Spbrook                 if (sig)
2513d08b2a28Spbrook                   {
2514d08b2a28Spbrook                     info.si_signo = sig;
2515d08b2a28Spbrook                     info.si_errno = 0;
2516d08b2a28Spbrook                     info.si_code = TARGET_TRAP_BRKPT;
2517624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2518d08b2a28Spbrook                   }
2519d08b2a28Spbrook             }
2520d08b2a28Spbrook             break;
2521590bc601SPaul Brook         case EXCP_SC:
2522590bc601SPaul Brook             if (do_store_exclusive(env)) {
2523590bc601SPaul Brook                 info.si_signo = TARGET_SIGSEGV;
2524590bc601SPaul Brook                 info.si_errno = 0;
2525590bc601SPaul Brook                 info.si_code = TARGET_SEGV_MAPERR;
2526590bc601SPaul Brook                 info._sifields._sigfault._addr = env->active_tc.PC;
2527590bc601SPaul Brook                 queue_signal(env, info.si_signo, &info);
2528590bc601SPaul Brook             }
2529590bc601SPaul Brook             break;
2530853c3240SJia Liu         case EXCP_DSPDIS:
2531853c3240SJia Liu             info.si_signo = TARGET_SIGILL;
2532853c3240SJia Liu             info.si_errno = 0;
2533853c3240SJia Liu             info.si_code = TARGET_ILL_ILLOPC;
2534853c3240SJia Liu             queue_signal(env, info.si_signo, &info);
2535853c3240SJia Liu             break;
253654b2f42cSMeador Inge         /* The code below was inspired by the MIPS Linux kernel trap
253754b2f42cSMeador Inge          * handling code in arch/mips/kernel/traps.c.
253854b2f42cSMeador Inge          */
253954b2f42cSMeador Inge         case EXCP_BREAK:
254054b2f42cSMeador Inge             {
254154b2f42cSMeador Inge                 abi_ulong trap_instr;
254254b2f42cSMeador Inge                 unsigned int code;
254354b2f42cSMeador Inge 
2544a0333817SKwok Cheung Yeung                 if (env->hflags & MIPS_HFLAG_M16) {
2545a0333817SKwok Cheung Yeung                     if (env->insn_flags & ASE_MICROMIPS) {
2546a0333817SKwok Cheung Yeung                         /* microMIPS mode */
25471308c464SKwok Cheung Yeung                         ret = get_user_u16(trap_instr, env->active_tc.PC);
25481308c464SKwok Cheung Yeung                         if (ret != 0) {
25491308c464SKwok Cheung Yeung                             goto error;
25501308c464SKwok Cheung Yeung                         }
2551a0333817SKwok Cheung Yeung 
25521308c464SKwok Cheung Yeung                         if ((trap_instr >> 10) == 0x11) {
25531308c464SKwok Cheung Yeung                             /* 16-bit instruction */
25541308c464SKwok Cheung Yeung                             code = trap_instr & 0xf;
25551308c464SKwok Cheung Yeung                         } else {
25561308c464SKwok Cheung Yeung                             /* 32-bit instruction */
25571308c464SKwok Cheung Yeung                             abi_ulong instr_lo;
2558a0333817SKwok Cheung Yeung 
25591308c464SKwok Cheung Yeung                             ret = get_user_u16(instr_lo,
25601308c464SKwok Cheung Yeung                                                env->active_tc.PC + 2);
25611308c464SKwok Cheung Yeung                             if (ret != 0) {
25621308c464SKwok Cheung Yeung                                 goto error;
25631308c464SKwok Cheung Yeung                             }
25641308c464SKwok Cheung Yeung                             trap_instr = (trap_instr << 16) | instr_lo;
25651308c464SKwok Cheung Yeung                             code = ((trap_instr >> 6) & ((1 << 20) - 1));
25661308c464SKwok Cheung Yeung                             /* Unfortunately, microMIPS also suffers from
25671308c464SKwok Cheung Yeung                                the old assembler bug...  */
25681308c464SKwok Cheung Yeung                             if (code >= (1 << 10)) {
25691308c464SKwok Cheung Yeung                                 code >>= 10;
25701308c464SKwok Cheung Yeung                             }
25711308c464SKwok Cheung Yeung                         }
2572a0333817SKwok Cheung Yeung                     } else {
2573a0333817SKwok Cheung Yeung                         /* MIPS16e mode */
2574a0333817SKwok Cheung Yeung                         ret = get_user_u16(trap_instr, env->active_tc.PC);
2575a0333817SKwok Cheung Yeung                         if (ret != 0) {
2576a0333817SKwok Cheung Yeung                             goto error;
2577a0333817SKwok Cheung Yeung                         }
2578a0333817SKwok Cheung Yeung                         code = (trap_instr >> 6) & 0x3f;
2579a0333817SKwok Cheung Yeung                     }
2580a0333817SKwok Cheung Yeung                 } else {
2581f01a361bSAndrew Bennett                     ret = get_user_u32(trap_instr, env->active_tc.PC);
258254b2f42cSMeador Inge                     if (ret != 0) {
258354b2f42cSMeador Inge                         goto error;
258454b2f42cSMeador Inge                     }
258554b2f42cSMeador Inge 
258654b2f42cSMeador Inge                     /* As described in the original Linux kernel code, the
258754b2f42cSMeador Inge                      * below checks on 'code' are to work around an old
258854b2f42cSMeador Inge                      * assembly bug.
258954b2f42cSMeador Inge                      */
259054b2f42cSMeador Inge                     code = ((trap_instr >> 6) & ((1 << 20) - 1));
259154b2f42cSMeador Inge                     if (code >= (1 << 10)) {
259254b2f42cSMeador Inge                         code >>= 10;
259354b2f42cSMeador Inge                     }
25941308c464SKwok Cheung Yeung                 }
259554b2f42cSMeador Inge 
259654b2f42cSMeador Inge                 if (do_break(env, &info, code) != 0) {
259754b2f42cSMeador Inge                     goto error;
259854b2f42cSMeador Inge                 }
259954b2f42cSMeador Inge             }
260054b2f42cSMeador Inge             break;
260154b2f42cSMeador Inge         case EXCP_TRAP:
260254b2f42cSMeador Inge             {
260354b2f42cSMeador Inge                 abi_ulong trap_instr;
260454b2f42cSMeador Inge                 unsigned int code = 0;
260554b2f42cSMeador Inge 
2606a0333817SKwok Cheung Yeung                 if (env->hflags & MIPS_HFLAG_M16) {
2607a0333817SKwok Cheung Yeung                     /* microMIPS mode */
2608a0333817SKwok Cheung Yeung                     abi_ulong instr[2];
2609a0333817SKwok Cheung Yeung 
2610a0333817SKwok Cheung Yeung                     ret = get_user_u16(instr[0], env->active_tc.PC) ||
2611a0333817SKwok Cheung Yeung                           get_user_u16(instr[1], env->active_tc.PC + 2);
2612a0333817SKwok Cheung Yeung 
2613a0333817SKwok Cheung Yeung                     trap_instr = (instr[0] << 16) | instr[1];
2614a0333817SKwok Cheung Yeung                 } else {
2615f01a361bSAndrew Bennett                     ret = get_user_u32(trap_instr, env->active_tc.PC);
2616a0333817SKwok Cheung Yeung                 }
2617a0333817SKwok Cheung Yeung 
261854b2f42cSMeador Inge                 if (ret != 0) {
261954b2f42cSMeador Inge                     goto error;
262054b2f42cSMeador Inge                 }
262154b2f42cSMeador Inge 
262254b2f42cSMeador Inge                 /* The immediate versions don't provide a code.  */
262354b2f42cSMeador Inge                 if (!(trap_instr & 0xFC000000)) {
2624a0333817SKwok Cheung Yeung                     if (env->hflags & MIPS_HFLAG_M16) {
2625a0333817SKwok Cheung Yeung                         /* microMIPS mode */
2626a0333817SKwok Cheung Yeung                         code = ((trap_instr >> 12) & ((1 << 4) - 1));
2627a0333817SKwok Cheung Yeung                     } else {
262854b2f42cSMeador Inge                         code = ((trap_instr >> 6) & ((1 << 10) - 1));
262954b2f42cSMeador Inge                     }
2630a0333817SKwok Cheung Yeung                 }
263154b2f42cSMeador Inge 
263254b2f42cSMeador Inge                 if (do_break(env, &info, code) != 0) {
263354b2f42cSMeador Inge                     goto error;
263454b2f42cSMeador Inge                 }
263554b2f42cSMeador Inge             }
263654b2f42cSMeador Inge             break;
2637048f6b4dSbellard         default:
263854b2f42cSMeador Inge error:
2639048f6b4dSbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2640048f6b4dSbellard                     trapnr);
2641878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
2642048f6b4dSbellard             abort();
2643048f6b4dSbellard         }
2644048f6b4dSbellard         process_pending_signals(env);
2645048f6b4dSbellard     }
2646048f6b4dSbellard }
2647048f6b4dSbellard #endif
2648048f6b4dSbellard 
2649d962783eSJia Liu #ifdef TARGET_OPENRISC
2650d962783eSJia Liu 
2651d962783eSJia Liu void cpu_loop(CPUOpenRISCState *env)
2652d962783eSJia Liu {
2653878096eeSAndreas Färber     CPUState *cs = CPU(openrisc_env_get_cpu(env));
2654d962783eSJia Liu     int trapnr, gdbsig;
2655d962783eSJia Liu 
2656d962783eSJia Liu     for (;;) {
2657b040bc9cSPeter Maydell         cpu_exec_start(cs);
2658ea3e9847SPeter Crosthwaite         trapnr = cpu_openrisc_exec(cs);
2659b040bc9cSPeter Maydell         cpu_exec_end(cs);
2660d962783eSJia Liu         gdbsig = 0;
2661d962783eSJia Liu 
2662d962783eSJia Liu         switch (trapnr) {
2663d962783eSJia Liu         case EXCP_RESET:
2664d962783eSJia Liu             qemu_log("\nReset request, exit, pc is %#x\n", env->pc);
26654d1275c2SRiku Voipio             exit(EXIT_FAILURE);
2666d962783eSJia Liu             break;
2667d962783eSJia Liu         case EXCP_BUSERR:
2668d962783eSJia Liu             qemu_log("\nBus error, exit, pc is %#x\n", env->pc);
2669a86b3c64SChen Gang S             gdbsig = TARGET_SIGBUS;
2670d962783eSJia Liu             break;
2671d962783eSJia Liu         case EXCP_DPF:
2672d962783eSJia Liu         case EXCP_IPF:
2673878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
2674d962783eSJia Liu             gdbsig = TARGET_SIGSEGV;
2675d962783eSJia Liu             break;
2676d962783eSJia Liu         case EXCP_TICK:
2677d962783eSJia Liu             qemu_log("\nTick time interrupt pc is %#x\n", env->pc);
2678d962783eSJia Liu             break;
2679d962783eSJia Liu         case EXCP_ALIGN:
2680d962783eSJia Liu             qemu_log("\nAlignment pc is %#x\n", env->pc);
2681a86b3c64SChen Gang S             gdbsig = TARGET_SIGBUS;
2682d962783eSJia Liu             break;
2683d962783eSJia Liu         case EXCP_ILLEGAL:
2684d962783eSJia Liu             qemu_log("\nIllegal instructionpc is %#x\n", env->pc);
2685a86b3c64SChen Gang S             gdbsig = TARGET_SIGILL;
2686d962783eSJia Liu             break;
2687d962783eSJia Liu         case EXCP_INT:
2688d962783eSJia Liu             qemu_log("\nExternal interruptpc is %#x\n", env->pc);
2689d962783eSJia Liu             break;
2690d962783eSJia Liu         case EXCP_DTLBMISS:
2691d962783eSJia Liu         case EXCP_ITLBMISS:
2692d962783eSJia Liu             qemu_log("\nTLB miss\n");
2693d962783eSJia Liu             break;
2694d962783eSJia Liu         case EXCP_RANGE:
2695d962783eSJia Liu             qemu_log("\nRange\n");
2696a86b3c64SChen Gang S             gdbsig = TARGET_SIGSEGV;
2697d962783eSJia Liu             break;
2698d962783eSJia Liu         case EXCP_SYSCALL:
2699d962783eSJia Liu             env->pc += 4;   /* 0xc00; */
2700d962783eSJia Liu             env->gpr[11] = do_syscall(env,
2701d962783eSJia Liu                                       env->gpr[11], /* return value       */
2702d962783eSJia Liu                                       env->gpr[3],  /* r3 - r7 are params */
2703d962783eSJia Liu                                       env->gpr[4],
2704d962783eSJia Liu                                       env->gpr[5],
2705d962783eSJia Liu                                       env->gpr[6],
2706d962783eSJia Liu                                       env->gpr[7],
2707d962783eSJia Liu                                       env->gpr[8], 0, 0);
2708d962783eSJia Liu             break;
2709d962783eSJia Liu         case EXCP_FPE:
2710d962783eSJia Liu             qemu_log("\nFloating point error\n");
2711d962783eSJia Liu             break;
2712d962783eSJia Liu         case EXCP_TRAP:
2713d962783eSJia Liu             qemu_log("\nTrap\n");
2714a86b3c64SChen Gang S             gdbsig = TARGET_SIGTRAP;
2715d962783eSJia Liu             break;
2716d962783eSJia Liu         case EXCP_NR:
2717d962783eSJia Liu             qemu_log("\nNR\n");
2718d962783eSJia Liu             break;
2719d962783eSJia Liu         default:
2720d962783eSJia Liu             qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n",
2721d962783eSJia Liu                      trapnr);
2722878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
2723d962783eSJia Liu             gdbsig = TARGET_SIGILL;
2724d962783eSJia Liu             break;
2725d962783eSJia Liu         }
2726d962783eSJia Liu         if (gdbsig) {
2727db6b81d4SAndreas Färber             gdb_handlesig(cs, gdbsig);
2728d962783eSJia Liu             if (gdbsig != TARGET_SIGTRAP) {
27294d1275c2SRiku Voipio                 exit(EXIT_FAILURE);
2730d962783eSJia Liu             }
2731d962783eSJia Liu         }
2732d962783eSJia Liu 
2733d962783eSJia Liu         process_pending_signals(env);
2734d962783eSJia Liu     }
2735d962783eSJia Liu }
2736d962783eSJia Liu 
2737d962783eSJia Liu #endif /* TARGET_OPENRISC */
2738d962783eSJia Liu 
2739fdf9b3e8Sbellard #ifdef TARGET_SH4
274005390248SAndreas Färber void cpu_loop(CPUSH4State *env)
2741fdf9b3e8Sbellard {
2742878096eeSAndreas Färber     CPUState *cs = CPU(sh_env_get_cpu(env));
2743fdf9b3e8Sbellard     int trapnr, ret;
2744c227f099SAnthony Liguori     target_siginfo_t info;
2745fdf9b3e8Sbellard 
2746fdf9b3e8Sbellard     while (1) {
2747b040bc9cSPeter Maydell         cpu_exec_start(cs);
2748ea3e9847SPeter Crosthwaite         trapnr = cpu_sh4_exec(cs);
2749b040bc9cSPeter Maydell         cpu_exec_end(cs);
2750fdf9b3e8Sbellard 
2751fdf9b3e8Sbellard         switch (trapnr) {
2752fdf9b3e8Sbellard         case 0x160:
27530b6d3ae0Saurel32             env->pc += 2;
2754fdf9b3e8Sbellard             ret = do_syscall(env,
27559c2a9ea1Spbrook                              env->gregs[3],
27569c2a9ea1Spbrook                              env->gregs[4],
27579c2a9ea1Spbrook                              env->gregs[5],
27589c2a9ea1Spbrook                              env->gregs[6],
27599c2a9ea1Spbrook                              env->gregs[7],
27609c2a9ea1Spbrook                              env->gregs[0],
27615945cfcbSPeter Maydell                              env->gregs[1],
27625945cfcbSPeter Maydell                              0, 0);
27639c2a9ea1Spbrook             env->gregs[0] = ret;
2764fdf9b3e8Sbellard             break;
2765c3b5bc8aSths         case EXCP_INTERRUPT:
2766c3b5bc8aSths             /* just indicate that signals should be handled asap */
2767c3b5bc8aSths             break;
2768355fb23dSpbrook         case EXCP_DEBUG:
2769355fb23dSpbrook             {
2770355fb23dSpbrook                 int sig;
2771355fb23dSpbrook 
2772db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
2773355fb23dSpbrook                 if (sig)
2774355fb23dSpbrook                   {
2775355fb23dSpbrook                     info.si_signo = sig;
2776355fb23dSpbrook                     info.si_errno = 0;
2777355fb23dSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2778624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2779355fb23dSpbrook                   }
2780355fb23dSpbrook             }
2781355fb23dSpbrook             break;
2782c3b5bc8aSths 	case 0xa0:
2783c3b5bc8aSths 	case 0xc0:
2784a86b3c64SChen Gang S             info.si_signo = TARGET_SIGSEGV;
2785c3b5bc8aSths             info.si_errno = 0;
2786c3b5bc8aSths             info.si_code = TARGET_SEGV_MAPERR;
2787c3b5bc8aSths             info._sifields._sigfault._addr = env->tea;
2788624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2789c3b5bc8aSths 	    break;
2790c3b5bc8aSths 
2791fdf9b3e8Sbellard         default:
2792fdf9b3e8Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
2793878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
27944d1275c2SRiku Voipio             exit(EXIT_FAILURE);
2795fdf9b3e8Sbellard         }
2796fdf9b3e8Sbellard         process_pending_signals (env);
2797fdf9b3e8Sbellard     }
2798fdf9b3e8Sbellard }
2799fdf9b3e8Sbellard #endif
2800fdf9b3e8Sbellard 
280148733d19Sths #ifdef TARGET_CRIS
280205390248SAndreas Färber void cpu_loop(CPUCRISState *env)
280348733d19Sths {
2804878096eeSAndreas Färber     CPUState *cs = CPU(cris_env_get_cpu(env));
280548733d19Sths     int trapnr, ret;
2806c227f099SAnthony Liguori     target_siginfo_t info;
280748733d19Sths 
280848733d19Sths     while (1) {
2809b040bc9cSPeter Maydell         cpu_exec_start(cs);
2810ea3e9847SPeter Crosthwaite         trapnr = cpu_cris_exec(cs);
2811b040bc9cSPeter Maydell         cpu_exec_end(cs);
281248733d19Sths         switch (trapnr) {
281348733d19Sths         case 0xaa:
281448733d19Sths             {
2815a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGSEGV;
281648733d19Sths                 info.si_errno = 0;
281748733d19Sths                 /* XXX: check env->error_code */
281848733d19Sths                 info.si_code = TARGET_SEGV_MAPERR;
2819e00c1e71Sedgar_igl                 info._sifields._sigfault._addr = env->pregs[PR_EDA];
2820624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
282148733d19Sths             }
282248733d19Sths             break;
2823b6d3abdaSedgar_igl 	case EXCP_INTERRUPT:
2824b6d3abdaSedgar_igl 	  /* just indicate that signals should be handled asap */
2825b6d3abdaSedgar_igl 	  break;
282648733d19Sths         case EXCP_BREAK:
282748733d19Sths             ret = do_syscall(env,
282848733d19Sths                              env->regs[9],
282948733d19Sths                              env->regs[10],
283048733d19Sths                              env->regs[11],
283148733d19Sths                              env->regs[12],
283248733d19Sths                              env->regs[13],
283348733d19Sths                              env->pregs[7],
28345945cfcbSPeter Maydell                              env->pregs[11],
28355945cfcbSPeter Maydell                              0, 0);
283648733d19Sths             env->regs[10] = ret;
283748733d19Sths             break;
283848733d19Sths         case EXCP_DEBUG:
283948733d19Sths             {
284048733d19Sths                 int sig;
284148733d19Sths 
2842db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
284348733d19Sths                 if (sig)
284448733d19Sths                   {
284548733d19Sths                     info.si_signo = sig;
284648733d19Sths                     info.si_errno = 0;
284748733d19Sths                     info.si_code = TARGET_TRAP_BRKPT;
2848624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
284948733d19Sths                   }
285048733d19Sths             }
285148733d19Sths             break;
285248733d19Sths         default:
285348733d19Sths             printf ("Unhandled trap: 0x%x\n", trapnr);
2854878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
28554d1275c2SRiku Voipio             exit(EXIT_FAILURE);
285648733d19Sths         }
285748733d19Sths         process_pending_signals (env);
285848733d19Sths     }
285948733d19Sths }
286048733d19Sths #endif
286148733d19Sths 
2862b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
286305390248SAndreas Färber void cpu_loop(CPUMBState *env)
2864b779e29eSEdgar E. Iglesias {
2865878096eeSAndreas Färber     CPUState *cs = CPU(mb_env_get_cpu(env));
2866b779e29eSEdgar E. Iglesias     int trapnr, ret;
2867c227f099SAnthony Liguori     target_siginfo_t info;
2868b779e29eSEdgar E. Iglesias 
2869b779e29eSEdgar E. Iglesias     while (1) {
2870b040bc9cSPeter Maydell         cpu_exec_start(cs);
2871ea3e9847SPeter Crosthwaite         trapnr = cpu_mb_exec(cs);
2872b040bc9cSPeter Maydell         cpu_exec_end(cs);
2873b779e29eSEdgar E. Iglesias         switch (trapnr) {
2874b779e29eSEdgar E. Iglesias         case 0xaa:
2875b779e29eSEdgar E. Iglesias             {
2876a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGSEGV;
2877b779e29eSEdgar E. Iglesias                 info.si_errno = 0;
2878b779e29eSEdgar E. Iglesias                 /* XXX: check env->error_code */
2879b779e29eSEdgar E. Iglesias                 info.si_code = TARGET_SEGV_MAPERR;
2880b779e29eSEdgar E. Iglesias                 info._sifields._sigfault._addr = 0;
2881b779e29eSEdgar E. Iglesias                 queue_signal(env, info.si_signo, &info);
2882b779e29eSEdgar E. Iglesias             }
2883b779e29eSEdgar E. Iglesias             break;
2884b779e29eSEdgar E. Iglesias 	case EXCP_INTERRUPT:
2885b779e29eSEdgar E. Iglesias 	  /* just indicate that signals should be handled asap */
2886b779e29eSEdgar E. Iglesias 	  break;
2887b779e29eSEdgar E. Iglesias         case EXCP_BREAK:
2888b779e29eSEdgar E. Iglesias             /* Return address is 4 bytes after the call.  */
2889b779e29eSEdgar E. Iglesias             env->regs[14] += 4;
2890d7dce494SEdgar E. Iglesias             env->sregs[SR_PC] = env->regs[14];
2891b779e29eSEdgar E. Iglesias             ret = do_syscall(env,
2892b779e29eSEdgar E. Iglesias                              env->regs[12],
2893b779e29eSEdgar E. Iglesias                              env->regs[5],
2894b779e29eSEdgar E. Iglesias                              env->regs[6],
2895b779e29eSEdgar E. Iglesias                              env->regs[7],
2896b779e29eSEdgar E. Iglesias                              env->regs[8],
2897b779e29eSEdgar E. Iglesias                              env->regs[9],
28985945cfcbSPeter Maydell                              env->regs[10],
28995945cfcbSPeter Maydell                              0, 0);
2900b779e29eSEdgar E. Iglesias             env->regs[3] = ret;
2901b779e29eSEdgar E. Iglesias             break;
2902b76da7e3SEdgar E. Iglesias         case EXCP_HW_EXCP:
2903b76da7e3SEdgar E. Iglesias             env->regs[17] = env->sregs[SR_PC] + 4;
2904b76da7e3SEdgar E. Iglesias             if (env->iflags & D_FLAG) {
2905b76da7e3SEdgar E. Iglesias                 env->sregs[SR_ESR] |= 1 << 12;
2906b76da7e3SEdgar E. Iglesias                 env->sregs[SR_PC] -= 4;
2907b76da7e3SEdgar E. Iglesias                 /* FIXME: if branch was immed, replay the imm as well.  */
2908b76da7e3SEdgar E. Iglesias             }
2909b76da7e3SEdgar E. Iglesias 
2910b76da7e3SEdgar E. Iglesias             env->iflags &= ~(IMM_FLAG | D_FLAG);
2911b76da7e3SEdgar E. Iglesias 
2912b76da7e3SEdgar E. Iglesias             switch (env->sregs[SR_ESR] & 31) {
291322a78d64SEdgar E. Iglesias                 case ESR_EC_DIVZERO:
2914a86b3c64SChen Gang S                     info.si_signo = TARGET_SIGFPE;
291522a78d64SEdgar E. Iglesias                     info.si_errno = 0;
291622a78d64SEdgar E. Iglesias                     info.si_code = TARGET_FPE_FLTDIV;
291722a78d64SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
291822a78d64SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
291922a78d64SEdgar E. Iglesias                     break;
2920b76da7e3SEdgar E. Iglesias                 case ESR_EC_FPU:
2921a86b3c64SChen Gang S                     info.si_signo = TARGET_SIGFPE;
2922b76da7e3SEdgar E. Iglesias                     info.si_errno = 0;
2923b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_IO) {
2924b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTINV;
2925b76da7e3SEdgar E. Iglesias                     }
2926b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_DZ) {
2927b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTDIV;
2928b76da7e3SEdgar E. Iglesias                     }
2929b76da7e3SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
2930b76da7e3SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2931b76da7e3SEdgar E. Iglesias                     break;
2932b76da7e3SEdgar E. Iglesias                 default:
2933b76da7e3SEdgar E. Iglesias                     printf ("Unhandled hw-exception: 0x%x\n",
29342e42d52dSEdgar E. Iglesias                             env->sregs[SR_ESR] & ESR_EC_MASK);
2935878096eeSAndreas Färber                     cpu_dump_state(cs, stderr, fprintf, 0);
29364d1275c2SRiku Voipio                     exit(EXIT_FAILURE);
2937b76da7e3SEdgar E. Iglesias                     break;
2938b76da7e3SEdgar E. Iglesias             }
2939b76da7e3SEdgar E. Iglesias             break;
2940b779e29eSEdgar E. Iglesias         case EXCP_DEBUG:
2941b779e29eSEdgar E. Iglesias             {
2942b779e29eSEdgar E. Iglesias                 int sig;
2943b779e29eSEdgar E. Iglesias 
2944db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
2945b779e29eSEdgar E. Iglesias                 if (sig)
2946b779e29eSEdgar E. Iglesias                   {
2947b779e29eSEdgar E. Iglesias                     info.si_signo = sig;
2948b779e29eSEdgar E. Iglesias                     info.si_errno = 0;
2949b779e29eSEdgar E. Iglesias                     info.si_code = TARGET_TRAP_BRKPT;
2950b779e29eSEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2951b779e29eSEdgar E. Iglesias                   }
2952b779e29eSEdgar E. Iglesias             }
2953b779e29eSEdgar E. Iglesias             break;
2954b779e29eSEdgar E. Iglesias         default:
2955b779e29eSEdgar E. Iglesias             printf ("Unhandled trap: 0x%x\n", trapnr);
2956878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
29574d1275c2SRiku Voipio             exit(EXIT_FAILURE);
2958b779e29eSEdgar E. Iglesias         }
2959b779e29eSEdgar E. Iglesias         process_pending_signals (env);
2960b779e29eSEdgar E. Iglesias     }
2961b779e29eSEdgar E. Iglesias }
2962b779e29eSEdgar E. Iglesias #endif
2963b779e29eSEdgar E. Iglesias 
2964e6e5906bSpbrook #ifdef TARGET_M68K
2965e6e5906bSpbrook 
2966e6e5906bSpbrook void cpu_loop(CPUM68KState *env)
2967e6e5906bSpbrook {
2968878096eeSAndreas Färber     CPUState *cs = CPU(m68k_env_get_cpu(env));
2969e6e5906bSpbrook     int trapnr;
2970e6e5906bSpbrook     unsigned int n;
2971c227f099SAnthony Liguori     target_siginfo_t info;
29720429a971SAndreas Färber     TaskState *ts = cs->opaque;
2973e6e5906bSpbrook 
2974e6e5906bSpbrook     for(;;) {
2975b040bc9cSPeter Maydell         cpu_exec_start(cs);
2976ea3e9847SPeter Crosthwaite         trapnr = cpu_m68k_exec(cs);
2977b040bc9cSPeter Maydell         cpu_exec_end(cs);
2978e6e5906bSpbrook         switch(trapnr) {
2979e6e5906bSpbrook         case EXCP_ILLEGAL:
2980e6e5906bSpbrook             {
2981e6e5906bSpbrook                 if (ts->sim_syscalls) {
2982e6e5906bSpbrook                     uint16_t nr;
2983d8d5119cSPeter Maydell                     get_user_u16(nr, env->pc + 2);
2984e6e5906bSpbrook                     env->pc += 4;
2985e6e5906bSpbrook                     do_m68k_simcall(env, nr);
2986e6e5906bSpbrook                 } else {
2987e6e5906bSpbrook                     goto do_sigill;
2988e6e5906bSpbrook                 }
2989e6e5906bSpbrook             }
2990e6e5906bSpbrook             break;
2991a87295e8Spbrook         case EXCP_HALT_INSN:
2992e6e5906bSpbrook             /* Semihosing syscall.  */
2993a87295e8Spbrook             env->pc += 4;
2994e6e5906bSpbrook             do_m68k_semihosting(env, env->dregs[0]);
2995e6e5906bSpbrook             break;
2996e6e5906bSpbrook         case EXCP_LINEA:
2997e6e5906bSpbrook         case EXCP_LINEF:
2998e6e5906bSpbrook         case EXCP_UNSUPPORTED:
2999e6e5906bSpbrook         do_sigill:
3000a86b3c64SChen Gang S             info.si_signo = TARGET_SIGILL;
3001e6e5906bSpbrook             info.si_errno = 0;
3002e6e5906bSpbrook             info.si_code = TARGET_ILL_ILLOPN;
3003e6e5906bSpbrook             info._sifields._sigfault._addr = env->pc;
3004624f7979Spbrook             queue_signal(env, info.si_signo, &info);
3005e6e5906bSpbrook             break;
3006e6e5906bSpbrook         case EXCP_TRAP0:
3007e6e5906bSpbrook             {
3008e6e5906bSpbrook                 ts->sim_syscalls = 0;
3009e6e5906bSpbrook                 n = env->dregs[0];
3010e6e5906bSpbrook                 env->pc += 2;
3011e6e5906bSpbrook                 env->dregs[0] = do_syscall(env,
3012e6e5906bSpbrook                                           n,
3013e6e5906bSpbrook                                           env->dregs[1],
3014e6e5906bSpbrook                                           env->dregs[2],
3015e6e5906bSpbrook                                           env->dregs[3],
3016e6e5906bSpbrook                                           env->dregs[4],
3017e6e5906bSpbrook                                           env->dregs[5],
30185945cfcbSPeter Maydell                                           env->aregs[0],
30195945cfcbSPeter Maydell                                           0, 0);
3020e6e5906bSpbrook             }
3021e6e5906bSpbrook             break;
3022e6e5906bSpbrook         case EXCP_INTERRUPT:
3023e6e5906bSpbrook             /* just indicate that signals should be handled asap */
3024e6e5906bSpbrook             break;
3025e6e5906bSpbrook         case EXCP_ACCESS:
3026e6e5906bSpbrook             {
3027a86b3c64SChen Gang S                 info.si_signo = TARGET_SIGSEGV;
3028e6e5906bSpbrook                 info.si_errno = 0;
3029e6e5906bSpbrook                 /* XXX: check env->error_code */
3030e6e5906bSpbrook                 info.si_code = TARGET_SEGV_MAPERR;
3031e6e5906bSpbrook                 info._sifields._sigfault._addr = env->mmu.ar;
3032624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
3033e6e5906bSpbrook             }
3034e6e5906bSpbrook             break;
3035e6e5906bSpbrook         case EXCP_DEBUG:
3036e6e5906bSpbrook             {
3037e6e5906bSpbrook                 int sig;
3038e6e5906bSpbrook 
3039db6b81d4SAndreas Färber                 sig = gdb_handlesig(cs, TARGET_SIGTRAP);
3040e6e5906bSpbrook                 if (sig)
3041e6e5906bSpbrook                   {
3042e6e5906bSpbrook                     info.si_signo = sig;
3043e6e5906bSpbrook                     info.si_errno = 0;
3044e6e5906bSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
3045624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
3046e6e5906bSpbrook                   }
3047e6e5906bSpbrook             }
3048e6e5906bSpbrook             break;
3049e6e5906bSpbrook         default:
3050e6e5906bSpbrook             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
3051e6e5906bSpbrook                     trapnr);
3052878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
3053e6e5906bSpbrook             abort();
3054e6e5906bSpbrook         }
3055e6e5906bSpbrook         process_pending_signals(env);
3056e6e5906bSpbrook     }
3057e6e5906bSpbrook }
3058e6e5906bSpbrook #endif /* TARGET_M68K */
3059e6e5906bSpbrook 
30607a3148a9Sj_mayer #ifdef TARGET_ALPHA
30616910b8f6SRichard Henderson static void do_store_exclusive(CPUAlphaState *env, int reg, int quad)
30626910b8f6SRichard Henderson {
30636910b8f6SRichard Henderson     target_ulong addr, val, tmp;
30646910b8f6SRichard Henderson     target_siginfo_t info;
30656910b8f6SRichard Henderson     int ret = 0;
30666910b8f6SRichard Henderson 
30676910b8f6SRichard Henderson     addr = env->lock_addr;
30686910b8f6SRichard Henderson     tmp = env->lock_st_addr;
30696910b8f6SRichard Henderson     env->lock_addr = -1;
30706910b8f6SRichard Henderson     env->lock_st_addr = 0;
30716910b8f6SRichard Henderson 
30726910b8f6SRichard Henderson     start_exclusive();
30736910b8f6SRichard Henderson     mmap_lock();
30746910b8f6SRichard Henderson 
30756910b8f6SRichard Henderson     if (addr == tmp) {
30766910b8f6SRichard Henderson         if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
30776910b8f6SRichard Henderson             goto do_sigsegv;
30786910b8f6SRichard Henderson         }
30796910b8f6SRichard Henderson 
30806910b8f6SRichard Henderson         if (val == env->lock_value) {
30816910b8f6SRichard Henderson             tmp = env->ir[reg];
30826910b8f6SRichard Henderson             if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) {
30836910b8f6SRichard Henderson                 goto do_sigsegv;
30846910b8f6SRichard Henderson             }
30856910b8f6SRichard Henderson             ret = 1;
30866910b8f6SRichard Henderson         }
30876910b8f6SRichard Henderson     }
30886910b8f6SRichard Henderson     env->ir[reg] = ret;
30896910b8f6SRichard Henderson     env->pc += 4;
30906910b8f6SRichard Henderson 
30916910b8f6SRichard Henderson     mmap_unlock();
30926910b8f6SRichard Henderson     end_exclusive();
30936910b8f6SRichard Henderson     return;
30946910b8f6SRichard Henderson 
30956910b8f6SRichard Henderson  do_sigsegv:
30966910b8f6SRichard Henderson     mmap_unlock();
30976910b8f6SRichard Henderson     end_exclusive();
30986910b8f6SRichard Henderson 
30996910b8f6SRichard Henderson     info.si_signo = TARGET_SIGSEGV;
31006910b8f6SRichard Henderson     info.si_errno = 0;
31016910b8f6SRichard Henderson     info.si_code = TARGET_SEGV_MAPERR;
31026910b8f6SRichard Henderson     info._sifields._sigfault._addr = addr;
31036910b8f6SRichard Henderson     queue_signal(env, TARGET_SIGSEGV, &info);
31046910b8f6SRichard Henderson }
31056910b8f6SRichard Henderson 
310605390248SAndreas Färber void cpu_loop(CPUAlphaState *env)
31077a3148a9Sj_mayer {
3108878096eeSAndreas Färber     CPUState *cs = CPU(alpha_env_get_cpu(env));
3109e96efcfcSj_mayer     int trapnr;
3110c227f099SAnthony Liguori     target_siginfo_t info;
31116049f4f8SRichard Henderson     abi_long sysret;
31127a3148a9Sj_mayer 
31137a3148a9Sj_mayer     while (1) {
3114b040bc9cSPeter Maydell         cpu_exec_start(cs);
3115ea3e9847SPeter Crosthwaite         trapnr = cpu_alpha_exec(cs);
3116b040bc9cSPeter Maydell         cpu_exec_end(cs);
31177a3148a9Sj_mayer 
3118ac316ca4SRichard Henderson         /* All of the traps imply a transition through PALcode, which
3119ac316ca4SRichard Henderson            implies an REI instruction has been executed.  Which means
3120ac316ca4SRichard Henderson            that the intr_flag should be cleared.  */
3121ac316ca4SRichard Henderson         env->intr_flag = 0;
3122ac316ca4SRichard Henderson 
31237a3148a9Sj_mayer         switch (trapnr) {
31247a3148a9Sj_mayer         case EXCP_RESET:
31257a3148a9Sj_mayer             fprintf(stderr, "Reset requested. Exit\n");
31264d1275c2SRiku Voipio             exit(EXIT_FAILURE);
31277a3148a9Sj_mayer             break;
31287a3148a9Sj_mayer         case EXCP_MCHK:
31297a3148a9Sj_mayer             fprintf(stderr, "Machine check exception. Exit\n");
31304d1275c2SRiku Voipio             exit(EXIT_FAILURE);
31317a3148a9Sj_mayer             break;
313207b6c13bSRichard Henderson         case EXCP_SMP_INTERRUPT:
313307b6c13bSRichard Henderson         case EXCP_CLK_INTERRUPT:
313407b6c13bSRichard Henderson         case EXCP_DEV_INTERRUPT:
31357a3148a9Sj_mayer             fprintf(stderr, "External interrupt. Exit\n");
31364d1275c2SRiku Voipio             exit(EXIT_FAILURE);
31377a3148a9Sj_mayer             break;
313807b6c13bSRichard Henderson         case EXCP_MMFAULT:
31396910b8f6SRichard Henderson             env->lock_addr = -1;
31406049f4f8SRichard Henderson             info.si_signo = TARGET_SIGSEGV;
31416049f4f8SRichard Henderson             info.si_errno = 0;
3142129d8aa5SRichard Henderson             info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
31430be1d07cSRichard Henderson                             ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
3144129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
31456049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
31467a3148a9Sj_mayer             break;
31477a3148a9Sj_mayer         case EXCP_UNALIGN:
31486910b8f6SRichard Henderson             env->lock_addr = -1;
31496049f4f8SRichard Henderson             info.si_signo = TARGET_SIGBUS;
31506049f4f8SRichard Henderson             info.si_errno = 0;
31516049f4f8SRichard Henderson             info.si_code = TARGET_BUS_ADRALN;
3152129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
31536049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
31547a3148a9Sj_mayer             break;
31557a3148a9Sj_mayer         case EXCP_OPCDEC:
31566049f4f8SRichard Henderson         do_sigill:
31576910b8f6SRichard Henderson             env->lock_addr = -1;
31586049f4f8SRichard Henderson             info.si_signo = TARGET_SIGILL;
31596049f4f8SRichard Henderson             info.si_errno = 0;
31606049f4f8SRichard Henderson             info.si_code = TARGET_ILL_ILLOPC;
31616049f4f8SRichard Henderson             info._sifields._sigfault._addr = env->pc;
31626049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
31637a3148a9Sj_mayer             break;
316407b6c13bSRichard Henderson         case EXCP_ARITH:
316507b6c13bSRichard Henderson             env->lock_addr = -1;
316607b6c13bSRichard Henderson             info.si_signo = TARGET_SIGFPE;
316707b6c13bSRichard Henderson             info.si_errno = 0;
316807b6c13bSRichard Henderson             info.si_code = TARGET_FPE_FLTINV;
316907b6c13bSRichard Henderson             info._sifields._sigfault._addr = env->pc;
317007b6c13bSRichard Henderson             queue_signal(env, info.si_signo, &info);
317107b6c13bSRichard Henderson             break;
31727a3148a9Sj_mayer         case EXCP_FEN:
31736049f4f8SRichard Henderson             /* No-op.  Linux simply re-enables the FPU.  */
31747a3148a9Sj_mayer             break;
317507b6c13bSRichard Henderson         case EXCP_CALL_PAL:
31766910b8f6SRichard Henderson             env->lock_addr = -1;
317707b6c13bSRichard Henderson             switch (env->error_code) {
31786049f4f8SRichard Henderson             case 0x80:
31796049f4f8SRichard Henderson                 /* BPT */
31806049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
31816049f4f8SRichard Henderson                 info.si_errno = 0;
31826049f4f8SRichard Henderson                 info.si_code = TARGET_TRAP_BRKPT;
31836049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
31846049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
31856049f4f8SRichard Henderson                 break;
31866049f4f8SRichard Henderson             case 0x81:
31876049f4f8SRichard Henderson                 /* BUGCHK */
31886049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
31896049f4f8SRichard Henderson                 info.si_errno = 0;
31906049f4f8SRichard Henderson                 info.si_code = 0;
31916049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
31926049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
31936049f4f8SRichard Henderson                 break;
31946049f4f8SRichard Henderson             case 0x83:
31956049f4f8SRichard Henderson                 /* CALLSYS */
31966049f4f8SRichard Henderson                 trapnr = env->ir[IR_V0];
31976049f4f8SRichard Henderson                 sysret = do_syscall(env, trapnr,
31986049f4f8SRichard Henderson                                     env->ir[IR_A0], env->ir[IR_A1],
31996049f4f8SRichard Henderson                                     env->ir[IR_A2], env->ir[IR_A3],
32005945cfcbSPeter Maydell                                     env->ir[IR_A4], env->ir[IR_A5],
32015945cfcbSPeter Maydell                                     0, 0);
3202a5b3b13bSRichard Henderson                 if (trapnr == TARGET_NR_sigreturn
3203a5b3b13bSRichard Henderson                     || trapnr == TARGET_NR_rt_sigreturn) {
3204a5b3b13bSRichard Henderson                     break;
3205a5b3b13bSRichard Henderson                 }
3206a5b3b13bSRichard Henderson                 /* Syscall writes 0 to V0 to bypass error check, similar
32070e141977SRichard Henderson                    to how this is handled internal to Linux kernel.
32080e141977SRichard Henderson                    (Ab)use trapnr temporarily as boolean indicating error.  */
32090e141977SRichard Henderson                 trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
32100e141977SRichard Henderson                 env->ir[IR_V0] = (trapnr ? -sysret : sysret);
32110e141977SRichard Henderson                 env->ir[IR_A3] = trapnr;
32126049f4f8SRichard Henderson                 break;
32136049f4f8SRichard Henderson             case 0x86:
32146049f4f8SRichard Henderson                 /* IMB */
32156049f4f8SRichard Henderson                 /* ??? We can probably elide the code using page_unprotect
32166049f4f8SRichard Henderson                    that is checking for self-modifying code.  Instead we
32176049f4f8SRichard Henderson                    could simply call tb_flush here.  Until we work out the
32186049f4f8SRichard Henderson                    changes required to turn off the extra write protection,
32196049f4f8SRichard Henderson                    this can be a no-op.  */
32206049f4f8SRichard Henderson                 break;
32216049f4f8SRichard Henderson             case 0x9E:
32226049f4f8SRichard Henderson                 /* RDUNIQUE */
32236049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
32246049f4f8SRichard Henderson                 abort();
32256049f4f8SRichard Henderson             case 0x9F:
32266049f4f8SRichard Henderson                 /* WRUNIQUE */
32276049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
32286049f4f8SRichard Henderson                 abort();
32296049f4f8SRichard Henderson             case 0xAA:
32306049f4f8SRichard Henderson                 /* GENTRAP */
32316049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGFPE;
32326049f4f8SRichard Henderson                 switch (env->ir[IR_A0]) {
32336049f4f8SRichard Henderson                 case TARGET_GEN_INTOVF:
32346049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTOVF;
32356049f4f8SRichard Henderson                     break;
32366049f4f8SRichard Henderson                 case TARGET_GEN_INTDIV:
32376049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTDIV;
32386049f4f8SRichard Henderson                     break;
32396049f4f8SRichard Henderson                 case TARGET_GEN_FLTOVF:
32406049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTOVF;
32416049f4f8SRichard Henderson                     break;
32426049f4f8SRichard Henderson                 case TARGET_GEN_FLTUND:
32436049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTUND;
32446049f4f8SRichard Henderson                     break;
32456049f4f8SRichard Henderson                 case TARGET_GEN_FLTINV:
32466049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTINV;
32476049f4f8SRichard Henderson                     break;
32486049f4f8SRichard Henderson                 case TARGET_GEN_FLTINE:
32496049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTRES;
32506049f4f8SRichard Henderson                     break;
32516049f4f8SRichard Henderson                 case TARGET_GEN_ROPRAND:
32526049f4f8SRichard Henderson                     info.si_code = 0;
32536049f4f8SRichard Henderson                     break;
32546049f4f8SRichard Henderson                 default:
32556049f4f8SRichard Henderson                     info.si_signo = TARGET_SIGTRAP;
32566049f4f8SRichard Henderson                     info.si_code = 0;
32576049f4f8SRichard Henderson                     break;
32586049f4f8SRichard Henderson                 }
32596049f4f8SRichard Henderson                 info.si_errno = 0;
32606049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
32616049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
32626049f4f8SRichard Henderson                 break;
32636049f4f8SRichard Henderson             default:
32646049f4f8SRichard Henderson                 goto do_sigill;
32656049f4f8SRichard Henderson             }
32667a3148a9Sj_mayer             break;
32677a3148a9Sj_mayer         case EXCP_DEBUG:
3268db6b81d4SAndreas Färber             info.si_signo = gdb_handlesig(cs, TARGET_SIGTRAP);
32696049f4f8SRichard Henderson             if (info.si_signo) {
32706910b8f6SRichard Henderson                 env->lock_addr = -1;
32717a3148a9Sj_mayer                 info.si_errno = 0;
32727a3148a9Sj_mayer                 info.si_code = TARGET_TRAP_BRKPT;
3273624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
32747a3148a9Sj_mayer             }
32757a3148a9Sj_mayer             break;
32766910b8f6SRichard Henderson         case EXCP_STL_C:
32776910b8f6SRichard Henderson         case EXCP_STQ_C:
32786910b8f6SRichard Henderson             do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
32796910b8f6SRichard Henderson             break;
3280d0f20495SRichard Henderson         case EXCP_INTERRUPT:
3281d0f20495SRichard Henderson             /* Just indicate that signals should be handled asap.  */
3282d0f20495SRichard Henderson             break;
32837a3148a9Sj_mayer         default:
32847a3148a9Sj_mayer             printf ("Unhandled trap: 0x%x\n", trapnr);
3285878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
32864d1275c2SRiku Voipio             exit(EXIT_FAILURE);
32877a3148a9Sj_mayer         }
32887a3148a9Sj_mayer         process_pending_signals (env);
32897a3148a9Sj_mayer     }
32907a3148a9Sj_mayer }
32917a3148a9Sj_mayer #endif /* TARGET_ALPHA */
32927a3148a9Sj_mayer 
3293a4c075f1SUlrich Hecht #ifdef TARGET_S390X
3294a4c075f1SUlrich Hecht void cpu_loop(CPUS390XState *env)
3295a4c075f1SUlrich Hecht {
3296878096eeSAndreas Färber     CPUState *cs = CPU(s390_env_get_cpu(env));
3297d5a103cdSRichard Henderson     int trapnr, n, sig;
3298a4c075f1SUlrich Hecht     target_siginfo_t info;
3299d5a103cdSRichard Henderson     target_ulong addr;
3300a4c075f1SUlrich Hecht 
3301a4c075f1SUlrich Hecht     while (1) {
3302b040bc9cSPeter Maydell         cpu_exec_start(cs);
3303ea3e9847SPeter Crosthwaite         trapnr = cpu_s390x_exec(cs);
3304b040bc9cSPeter Maydell         cpu_exec_end(cs);
3305a4c075f1SUlrich Hecht         switch (trapnr) {
3306a4c075f1SUlrich Hecht         case EXCP_INTERRUPT:
3307d5a103cdSRichard Henderson             /* Just indicate that signals should be handled asap.  */
3308a4c075f1SUlrich Hecht             break;
3309a4c075f1SUlrich Hecht 
3310a4c075f1SUlrich Hecht         case EXCP_SVC:
3311d5a103cdSRichard Henderson             n = env->int_svc_code;
3312a4c075f1SUlrich Hecht             if (!n) {
3313a4c075f1SUlrich Hecht                 /* syscalls > 255 */
3314a4c075f1SUlrich Hecht                 n = env->regs[1];
3315a4c075f1SUlrich Hecht             }
3316d5a103cdSRichard Henderson             env->psw.addr += env->int_svc_ilen;
3317d5a103cdSRichard Henderson             env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3],
3318d5a103cdSRichard Henderson                                       env->regs[4], env->regs[5],
3319d5a103cdSRichard Henderson                                       env->regs[6], env->regs[7], 0, 0);
3320d5a103cdSRichard Henderson             break;
3321d5a103cdSRichard Henderson 
3322d5a103cdSRichard Henderson         case EXCP_DEBUG:
3323db6b81d4SAndreas Färber             sig = gdb_handlesig(cs, TARGET_SIGTRAP);
3324d5a103cdSRichard Henderson             if (sig) {
3325d5a103cdSRichard Henderson                 n = TARGET_TRAP_BRKPT;
3326d5a103cdSRichard Henderson                 goto do_signal_pc;
3327a4c075f1SUlrich Hecht             }
3328a4c075f1SUlrich Hecht             break;
3329d5a103cdSRichard Henderson         case EXCP_PGM:
3330d5a103cdSRichard Henderson             n = env->int_pgm_code;
3331d5a103cdSRichard Henderson             switch (n) {
3332d5a103cdSRichard Henderson             case PGM_OPERATION:
3333d5a103cdSRichard Henderson             case PGM_PRIVILEGED:
3334a86b3c64SChen Gang S                 sig = TARGET_SIGILL;
3335d5a103cdSRichard Henderson                 n = TARGET_ILL_ILLOPC;
3336d5a103cdSRichard Henderson                 goto do_signal_pc;
3337d5a103cdSRichard Henderson             case PGM_PROTECTION:
3338d5a103cdSRichard Henderson             case PGM_ADDRESSING:
3339a86b3c64SChen Gang S                 sig = TARGET_SIGSEGV;
3340a4c075f1SUlrich Hecht                 /* XXX: check env->error_code */
3341d5a103cdSRichard Henderson                 n = TARGET_SEGV_MAPERR;
3342d5a103cdSRichard Henderson                 addr = env->__excp_addr;
3343d5a103cdSRichard Henderson                 goto do_signal;
3344d5a103cdSRichard Henderson             case PGM_EXECUTE:
3345d5a103cdSRichard Henderson             case PGM_SPECIFICATION:
3346d5a103cdSRichard Henderson             case PGM_SPECIAL_OP:
3347d5a103cdSRichard Henderson             case PGM_OPERAND:
3348d5a103cdSRichard Henderson             do_sigill_opn:
3349a86b3c64SChen Gang S                 sig = TARGET_SIGILL;
3350d5a103cdSRichard Henderson                 n = TARGET_ILL_ILLOPN;
3351d5a103cdSRichard Henderson                 goto do_signal_pc;
3352d5a103cdSRichard Henderson 
3353d5a103cdSRichard Henderson             case PGM_FIXPT_OVERFLOW:
3354a86b3c64SChen Gang S                 sig = TARGET_SIGFPE;
3355d5a103cdSRichard Henderson                 n = TARGET_FPE_INTOVF;
3356d5a103cdSRichard Henderson                 goto do_signal_pc;
3357d5a103cdSRichard Henderson             case PGM_FIXPT_DIVIDE:
3358a86b3c64SChen Gang S                 sig = TARGET_SIGFPE;
3359d5a103cdSRichard Henderson                 n = TARGET_FPE_INTDIV;
3360d5a103cdSRichard Henderson                 goto do_signal_pc;
3361d5a103cdSRichard Henderson 
3362d5a103cdSRichard Henderson             case PGM_DATA:
3363d5a103cdSRichard Henderson                 n = (env->fpc >> 8) & 0xff;
3364d5a103cdSRichard Henderson                 if (n == 0xff) {
3365d5a103cdSRichard Henderson                     /* compare-and-trap */
3366d5a103cdSRichard Henderson                     goto do_sigill_opn;
3367d5a103cdSRichard Henderson                 } else {
3368d5a103cdSRichard Henderson                     /* An IEEE exception, simulated or otherwise.  */
3369d5a103cdSRichard Henderson                     if (n & 0x80) {
3370d5a103cdSRichard Henderson                         n = TARGET_FPE_FLTINV;
3371d5a103cdSRichard Henderson                     } else if (n & 0x40) {
3372d5a103cdSRichard Henderson                         n = TARGET_FPE_FLTDIV;
3373d5a103cdSRichard Henderson                     } else if (n & 0x20) {
3374d5a103cdSRichard Henderson                         n = TARGET_FPE_FLTOVF;
3375d5a103cdSRichard Henderson                     } else if (n & 0x10) {
3376d5a103cdSRichard Henderson                         n = TARGET_FPE_FLTUND;
3377d5a103cdSRichard Henderson                     } else if (n & 0x08) {
3378d5a103cdSRichard Henderson                         n = TARGET_FPE_FLTRES;
3379d5a103cdSRichard Henderson                     } else {
3380d5a103cdSRichard Henderson                         /* ??? Quantum exception; BFP, DFP error.  */
3381d5a103cdSRichard Henderson                         goto do_sigill_opn;
3382a4c075f1SUlrich Hecht                     }
3383a86b3c64SChen Gang S                     sig = TARGET_SIGFPE;
3384d5a103cdSRichard Henderson                     goto do_signal_pc;
3385a4c075f1SUlrich Hecht                 }
3386d5a103cdSRichard Henderson 
3387a4c075f1SUlrich Hecht             default:
3388d5a103cdSRichard Henderson                 fprintf(stderr, "Unhandled program exception: %#x\n", n);
3389878096eeSAndreas Färber                 cpu_dump_state(cs, stderr, fprintf, 0);
33904d1275c2SRiku Voipio                 exit(EXIT_FAILURE);
3391d5a103cdSRichard Henderson             }
3392d5a103cdSRichard Henderson             break;
3393d5a103cdSRichard Henderson 
3394d5a103cdSRichard Henderson         do_signal_pc:
3395d5a103cdSRichard Henderson             addr = env->psw.addr;
3396d5a103cdSRichard Henderson         do_signal:
3397d5a103cdSRichard Henderson             info.si_signo = sig;
3398d5a103cdSRichard Henderson             info.si_errno = 0;
3399d5a103cdSRichard Henderson             info.si_code = n;
3400d5a103cdSRichard Henderson             info._sifields._sigfault._addr = addr;
3401d5a103cdSRichard Henderson             queue_signal(env, info.si_signo, &info);
3402d5a103cdSRichard Henderson             break;
3403d5a103cdSRichard Henderson 
3404d5a103cdSRichard Henderson         default:
3405d5a103cdSRichard Henderson             fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
3406878096eeSAndreas Färber             cpu_dump_state(cs, stderr, fprintf, 0);
34074d1275c2SRiku Voipio             exit(EXIT_FAILURE);
3408a4c075f1SUlrich Hecht         }
3409a4c075f1SUlrich Hecht         process_pending_signals (env);
3410a4c075f1SUlrich Hecht     }
3411a4c075f1SUlrich Hecht }
3412a4c075f1SUlrich Hecht 
3413a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
3414a4c075f1SUlrich Hecht 
3415b16189b2SChen Gang #ifdef TARGET_TILEGX
3416b16189b2SChen Gang 
3417b16189b2SChen Gang static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
3418b16189b2SChen Gang {
3419b16189b2SChen Gang     target_siginfo_t info;
3420b16189b2SChen Gang 
3421b16189b2SChen Gang     info.si_signo = TARGET_SIGSEGV;
3422b16189b2SChen Gang     info.si_errno = 0;
3423b16189b2SChen Gang     info.si_code = TARGET_SEGV_MAPERR;
3424b16189b2SChen Gang     info._sifields._sigfault._addr = addr;
3425b16189b2SChen Gang     queue_signal(env, info.si_signo, &info);
3426b16189b2SChen Gang }
3427b16189b2SChen Gang 
3428b16189b2SChen Gang static void gen_sigill_reg(CPUTLGState *env)
3429b16189b2SChen Gang {
3430b16189b2SChen Gang     target_siginfo_t info;
3431b16189b2SChen Gang 
3432b16189b2SChen Gang     info.si_signo = TARGET_SIGILL;
3433b16189b2SChen Gang     info.si_errno = 0;
3434b16189b2SChen Gang     info.si_code = TARGET_ILL_PRVREG;
3435b16189b2SChen Gang     info._sifields._sigfault._addr = env->pc;
3436b16189b2SChen Gang     queue_signal(env, info.si_signo, &info);
3437b16189b2SChen Gang }
3438b16189b2SChen Gang 
34390583b233SRichard Henderson static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
34400583b233SRichard Henderson {
34410583b233SRichard Henderson     if (unlikely(reg >= TILEGX_R_COUNT)) {
34420583b233SRichard Henderson         switch (reg) {
34430583b233SRichard Henderson         case TILEGX_R_SN:
34440583b233SRichard Henderson         case TILEGX_R_ZERO:
34450583b233SRichard Henderson             return;
34460583b233SRichard Henderson         case TILEGX_R_IDN0:
34470583b233SRichard Henderson         case TILEGX_R_IDN1:
34480583b233SRichard Henderson         case TILEGX_R_UDN0:
34490583b233SRichard Henderson         case TILEGX_R_UDN1:
34500583b233SRichard Henderson         case TILEGX_R_UDN2:
34510583b233SRichard Henderson         case TILEGX_R_UDN3:
34520583b233SRichard Henderson             gen_sigill_reg(env);
34530583b233SRichard Henderson             return;
34540583b233SRichard Henderson         default:
34550583b233SRichard Henderson             g_assert_not_reached();
34560583b233SRichard Henderson         }
34570583b233SRichard Henderson     }
34580583b233SRichard Henderson     env->regs[reg] = val;
34590583b233SRichard Henderson }
34600583b233SRichard Henderson 
34610583b233SRichard Henderson /*
34620583b233SRichard Henderson  * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
34630583b233SRichard Henderson  * memory at the address held in the first source register. If the values are
34640583b233SRichard Henderson  * not equal, then no memory operation is performed. If the values are equal,
34650583b233SRichard Henderson  * the 8-byte quantity from the second source register is written into memory
34660583b233SRichard Henderson  * at the address held in the first source register. In either case, the result
34670583b233SRichard Henderson  * of the instruction is the value read from memory. The compare and write to
34680583b233SRichard Henderson  * memory are atomic and thus can be used for synchronization purposes. This
34690583b233SRichard Henderson  * instruction only operates for addresses aligned to a 8-byte boundary.
34700583b233SRichard Henderson  * Unaligned memory access causes an Unaligned Data Reference interrupt.
34710583b233SRichard Henderson  *
34720583b233SRichard Henderson  * Functional Description (64-bit)
34730583b233SRichard Henderson  *       uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
34740583b233SRichard Henderson  *       rf[Dest] = memVal;
34750583b233SRichard Henderson  *       if (memVal == SPR[CmpValueSPR])
34760583b233SRichard Henderson  *           memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
34770583b233SRichard Henderson  *
34780583b233SRichard Henderson  * Functional Description (32-bit)
34790583b233SRichard Henderson  *       uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
34800583b233SRichard Henderson  *       rf[Dest] = memVal;
34810583b233SRichard Henderson  *       if (memVal == signExtend32 (SPR[CmpValueSPR]))
34820583b233SRichard Henderson  *           memoryWriteWord (rf[SrcA], rf[SrcB]);
34830583b233SRichard Henderson  *
34840583b233SRichard Henderson  *
34850583b233SRichard Henderson  * This function also processes exch and exch4 which need not process SPR.
34860583b233SRichard Henderson  */
34870583b233SRichard Henderson static void do_exch(CPUTLGState *env, bool quad, bool cmp)
34880583b233SRichard Henderson {
34890583b233SRichard Henderson     target_ulong addr;
34900583b233SRichard Henderson     target_long val, sprval;
34910583b233SRichard Henderson 
34920583b233SRichard Henderson     start_exclusive();
34930583b233SRichard Henderson 
34940583b233SRichard Henderson     addr = env->atomic_srca;
34950583b233SRichard Henderson     if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
34960583b233SRichard Henderson         goto sigsegv_maperr;
34970583b233SRichard Henderson     }
34980583b233SRichard Henderson 
34990583b233SRichard Henderson     if (cmp) {
35000583b233SRichard Henderson         if (quad) {
35010583b233SRichard Henderson             sprval = env->spregs[TILEGX_SPR_CMPEXCH];
35020583b233SRichard Henderson         } else {
35030583b233SRichard Henderson             sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
35040583b233SRichard Henderson         }
35050583b233SRichard Henderson     }
35060583b233SRichard Henderson 
35070583b233SRichard Henderson     if (!cmp || val == sprval) {
35080583b233SRichard Henderson         target_long valb = env->atomic_srcb;
35090583b233SRichard Henderson         if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
35100583b233SRichard Henderson             goto sigsegv_maperr;
35110583b233SRichard Henderson         }
35120583b233SRichard Henderson     }
35130583b233SRichard Henderson 
35140583b233SRichard Henderson     set_regval(env, env->atomic_dstr, val);
35150583b233SRichard Henderson     end_exclusive();
35160583b233SRichard Henderson     return;
35170583b233SRichard Henderson 
35180583b233SRichard Henderson  sigsegv_maperr:
35190583b233SRichard Henderson     end_exclusive();
35200583b233SRichard Henderson     gen_sigsegv_maperr(env, addr);
35210583b233SRichard Henderson }
35220583b233SRichard Henderson 
35230583b233SRichard Henderson static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
35240583b233SRichard Henderson {
35250583b233SRichard Henderson     int8_t write = 1;
35260583b233SRichard Henderson     target_ulong addr;
35270583b233SRichard Henderson     target_long val, valb;
35280583b233SRichard Henderson 
35290583b233SRichard Henderson     start_exclusive();
35300583b233SRichard Henderson 
35310583b233SRichard Henderson     addr = env->atomic_srca;
35320583b233SRichard Henderson     valb = env->atomic_srcb;
35330583b233SRichard Henderson     if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
35340583b233SRichard Henderson         goto sigsegv_maperr;
35350583b233SRichard Henderson     }
35360583b233SRichard Henderson 
35370583b233SRichard Henderson     switch (trapnr) {
35380583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHADD:
35390583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHADD4:
35400583b233SRichard Henderson         valb += val;
35410583b233SRichard Henderson         break;
35420583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
35430583b233SRichard Henderson         valb += val;
35440583b233SRichard Henderson         if (valb < 0) {
35450583b233SRichard Henderson             write = 0;
35460583b233SRichard Henderson         }
35470583b233SRichard Henderson         break;
35480583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
35490583b233SRichard Henderson         valb += val;
35500583b233SRichard Henderson         if ((int32_t)valb < 0) {
35510583b233SRichard Henderson             write = 0;
35520583b233SRichard Henderson         }
35530583b233SRichard Henderson         break;
35540583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHAND:
35550583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHAND4:
35560583b233SRichard Henderson         valb &= val;
35570583b233SRichard Henderson         break;
35580583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHOR:
35590583b233SRichard Henderson     case TILEGX_EXCP_OPCODE_FETCHOR4:
35600583b233SRichard Henderson         valb |= val;
35610583b233SRichard Henderson         break;
35620583b233SRichard Henderson     default:
35630583b233SRichard Henderson         g_assert_not_reached();
35640583b233SRichard Henderson     }
35650583b233SRichard Henderson 
35660583b233SRichard Henderson     if (write) {
35670583b233SRichard Henderson         if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
35680583b233SRichard Henderson             goto sigsegv_maperr;
35690583b233SRichard Henderson         }
35700583b233SRichard Henderson     }
35710583b233SRichard Henderson 
35720583b233SRichard Henderson     set_regval(env, env->atomic_dstr, val);
35730583b233SRichard Henderson     end_exclusive();
35740583b233SRichard Henderson     return;
35750583b233SRichard Henderson 
35760583b233SRichard Henderson  sigsegv_maperr:
35770583b233SRichard Henderson     end_exclusive();
35780583b233SRichard Henderson     gen_sigsegv_maperr(env, addr);
35790583b233SRichard Henderson }
35800583b233SRichard Henderson 
3581b16189b2SChen Gang void cpu_loop(CPUTLGState *env)
3582b16189b2SChen Gang {
3583b16189b2SChen Gang     CPUState *cs = CPU(tilegx_env_get_cpu(env));
3584b16189b2SChen Gang     int trapnr;
3585b16189b2SChen Gang 
3586b16189b2SChen Gang     while (1) {
3587b16189b2SChen Gang         cpu_exec_start(cs);
3588b16189b2SChen Gang         trapnr = cpu_tilegx_exec(cs);
3589b16189b2SChen Gang         cpu_exec_end(cs);
3590b16189b2SChen Gang         switch (trapnr) {
3591b16189b2SChen Gang         case TILEGX_EXCP_SYSCALL:
3592b16189b2SChen Gang             env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],
3593b16189b2SChen Gang                                                 env->regs[0], env->regs[1],
3594b16189b2SChen Gang                                                 env->regs[2], env->regs[3],
3595b16189b2SChen Gang                                                 env->regs[4], env->regs[5],
3596b16189b2SChen Gang                                                 env->regs[6], env->regs[7]);
3597b16189b2SChen Gang             env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])
3598b16189b2SChen Gang                                                       ? - env->regs[TILEGX_R_RE]
3599b16189b2SChen Gang                                                       : 0;
3600b16189b2SChen Gang             break;
36010583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_EXCH:
36020583b233SRichard Henderson             do_exch(env, true, false);
36030583b233SRichard Henderson             break;
36040583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_EXCH4:
36050583b233SRichard Henderson             do_exch(env, false, false);
36060583b233SRichard Henderson             break;
36070583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_CMPEXCH:
36080583b233SRichard Henderson             do_exch(env, true, true);
36090583b233SRichard Henderson             break;
36100583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_CMPEXCH4:
36110583b233SRichard Henderson             do_exch(env, false, true);
36120583b233SRichard Henderson             break;
36130583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHADD:
36140583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
36150583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHAND:
36160583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHOR:
36170583b233SRichard Henderson             do_fetch(env, trapnr, true);
36180583b233SRichard Henderson             break;
36190583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHADD4:
36200583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
36210583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHAND4:
36220583b233SRichard Henderson         case TILEGX_EXCP_OPCODE_FETCHOR4:
36230583b233SRichard Henderson             do_fetch(env, trapnr, false);
36240583b233SRichard Henderson             break;
3625b16189b2SChen Gang         case TILEGX_EXCP_REG_IDN_ACCESS:
3626b16189b2SChen Gang         case TILEGX_EXCP_REG_UDN_ACCESS:
3627b16189b2SChen Gang             gen_sigill_reg(env);
3628b16189b2SChen Gang             break;
36299b9dc7acSRichard Henderson         case TILEGX_EXCP_SEGV:
36309b9dc7acSRichard Henderson             gen_sigsegv_maperr(env, env->excaddr);
36319b9dc7acSRichard Henderson             break;
3632b16189b2SChen Gang         default:
3633b16189b2SChen Gang             fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
3634b16189b2SChen Gang             g_assert_not_reached();
3635b16189b2SChen Gang         }
3636b16189b2SChen Gang         process_pending_signals(env);
3637b16189b2SChen Gang     }
3638b16189b2SChen Gang }
3639b16189b2SChen Gang 
3640b16189b2SChen Gang #endif
3641b16189b2SChen Gang 
3642a2247f8eSAndreas Färber THREAD CPUState *thread_cpu;
364359faf6d6Sbellard 
3644edf8e2afSMika Westerberg void task_settid(TaskState *ts)
3645edf8e2afSMika Westerberg {
3646edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
3647edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
3648edf8e2afSMika Westerberg     }
3649edf8e2afSMika Westerberg }
3650edf8e2afSMika Westerberg 
3651edf8e2afSMika Westerberg void stop_all_tasks(void)
3652edf8e2afSMika Westerberg {
3653edf8e2afSMika Westerberg     /*
3654edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
3655edf8e2afSMika Westerberg      * handles thread stopping correctly.
3656edf8e2afSMika Westerberg      */
3657edf8e2afSMika Westerberg     start_exclusive();
3658edf8e2afSMika Westerberg }
3659edf8e2afSMika Westerberg 
3660c3a92833Spbrook /* Assumes contents are already zeroed.  */
3661624f7979Spbrook void init_task_state(TaskState *ts)
3662624f7979Spbrook {
3663624f7979Spbrook     int i;
3664624f7979Spbrook 
3665624f7979Spbrook     ts->used = 1;
3666624f7979Spbrook     ts->first_free = ts->sigqueue_table;
3667624f7979Spbrook     for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
3668624f7979Spbrook         ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
3669624f7979Spbrook     }
3670624f7979Spbrook     ts->sigqueue_table[i].next = NULL;
3671624f7979Spbrook }
36729de5e440Sbellard 
367330ba0ee5SAndreas Färber CPUArchState *cpu_copy(CPUArchState *env)
367430ba0ee5SAndreas Färber {
3675ff4700b0SAndreas Färber     CPUState *cpu = ENV_GET_CPU(env);
36762994fd96SEduardo Habkost     CPUState *new_cpu = cpu_init(cpu_model);
367761c7480fSLeon Alrae     CPUArchState *new_env = new_cpu->env_ptr;
367830ba0ee5SAndreas Färber     CPUBreakpoint *bp;
367930ba0ee5SAndreas Färber     CPUWatchpoint *wp;
368030ba0ee5SAndreas Färber 
368130ba0ee5SAndreas Färber     /* Reset non arch specific state */
368275a34036SAndreas Färber     cpu_reset(new_cpu);
368330ba0ee5SAndreas Färber 
368430ba0ee5SAndreas Färber     memcpy(new_env, env, sizeof(CPUArchState));
368530ba0ee5SAndreas Färber 
368630ba0ee5SAndreas Färber     /* Clone all break/watchpoints.
368730ba0ee5SAndreas Färber        Note: Once we support ptrace with hw-debug register access, make sure
368830ba0ee5SAndreas Färber        BP_CPU break/watchpoints are handled correctly on clone. */
36891d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->breakpoints);
36901d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->watchpoints);
3691f0c3c505SAndreas Färber     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
3692b3310ab3SAndreas Färber         cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
369330ba0ee5SAndreas Färber     }
3694ff4700b0SAndreas Färber     QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
369505068c0dSPeter Maydell         cpu_watchpoint_insert(new_cpu, wp->vaddr, wp->len, wp->flags, NULL);
369630ba0ee5SAndreas Färber     }
369730ba0ee5SAndreas Färber 
369830ba0ee5SAndreas Färber     return new_env;
369930ba0ee5SAndreas Färber }
370030ba0ee5SAndreas Färber 
3701fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
3702fc9c5412SJohannes Schauer {
37034d1275c2SRiku Voipio     usage(EXIT_SUCCESS);
3704fc9c5412SJohannes Schauer }
3705fc9c5412SJohannes Schauer 
3706fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
3707fc9c5412SJohannes Schauer {
3708fc9c5412SJohannes Schauer     int mask;
3709fc9c5412SJohannes Schauer 
37104fde1ebaSPeter Maydell     mask = qemu_str_to_log_mask(arg);
3711fc9c5412SJohannes Schauer     if (!mask) {
371259a6fa6eSPeter Maydell         qemu_print_log_usage(stdout);
37134d1275c2SRiku Voipio         exit(EXIT_FAILURE);
3714fc9c5412SJohannes Schauer     }
371524537a01SPeter Maydell     qemu_set_log(mask);
3716fc9c5412SJohannes Schauer }
3717fc9c5412SJohannes Schauer 
371850171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
371950171d42S陳韋任 {
37209a7e5424SPeter Maydell     qemu_set_log_filename(arg);
372150171d42S陳韋任 }
372250171d42S陳韋任 
3723fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
3724fc9c5412SJohannes Schauer {
3725fc9c5412SJohannes Schauer     char *r, *p, *token;
3726fc9c5412SJohannes Schauer     r = p = strdup(arg);
3727fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
3728fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
37294d1275c2SRiku Voipio             usage(EXIT_FAILURE);
3730fc9c5412SJohannes Schauer         }
3731fc9c5412SJohannes Schauer     }
3732fc9c5412SJohannes Schauer     free(r);
3733fc9c5412SJohannes Schauer }
3734fc9c5412SJohannes Schauer 
3735fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
3736fc9c5412SJohannes Schauer {
3737fc9c5412SJohannes Schauer     char *r, *p, *token;
3738fc9c5412SJohannes Schauer     r = p = strdup(arg);
3739fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
3740fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
37414d1275c2SRiku Voipio             usage(EXIT_FAILURE);
3742fc9c5412SJohannes Schauer         }
3743fc9c5412SJohannes Schauer     }
3744fc9c5412SJohannes Schauer     free(r);
3745fc9c5412SJohannes Schauer }
3746fc9c5412SJohannes Schauer 
3747fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
3748fc9c5412SJohannes Schauer {
3749fc9c5412SJohannes Schauer     argv0 = strdup(arg);
3750fc9c5412SJohannes Schauer }
3751fc9c5412SJohannes Schauer 
3752fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
3753fc9c5412SJohannes Schauer {
3754fc9c5412SJohannes Schauer     char *p;
3755fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
3756fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
37574d1275c2SRiku Voipio         usage(EXIT_FAILURE);
3758fc9c5412SJohannes Schauer     }
3759fc9c5412SJohannes Schauer 
3760fc9c5412SJohannes Schauer     if (*p == 'M') {
3761fc9c5412SJohannes Schauer         guest_stack_size *= 1024 * 1024;
3762fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
3763fc9c5412SJohannes Schauer         guest_stack_size *= 1024;
3764fc9c5412SJohannes Schauer     }
3765fc9c5412SJohannes Schauer }
3766fc9c5412SJohannes Schauer 
3767fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
3768fc9c5412SJohannes Schauer {
3769fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
3770fc9c5412SJohannes Schauer }
3771fc9c5412SJohannes Schauer 
3772fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
3773fc9c5412SJohannes Schauer {
3774fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
3775fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
3776fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
3777fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
37784d1275c2SRiku Voipio         exit(EXIT_FAILURE);
3779fc9c5412SJohannes Schauer     }
3780fc9c5412SJohannes Schauer }
3781fc9c5412SJohannes Schauer 
3782c5e4a5a9SMagnus Reftel static void handle_arg_randseed(const char *arg)
3783c5e4a5a9SMagnus Reftel {
3784c5e4a5a9SMagnus Reftel     unsigned long long seed;
3785c5e4a5a9SMagnus Reftel 
3786c5e4a5a9SMagnus Reftel     if (parse_uint_full(arg, &seed, 0) != 0 || seed > UINT_MAX) {
3787c5e4a5a9SMagnus Reftel         fprintf(stderr, "Invalid seed number: %s\n", arg);
37884d1275c2SRiku Voipio         exit(EXIT_FAILURE);
3789c5e4a5a9SMagnus Reftel     }
3790c5e4a5a9SMagnus Reftel     srand(seed);
3791c5e4a5a9SMagnus Reftel }
3792c5e4a5a9SMagnus Reftel 
3793fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
3794fc9c5412SJohannes Schauer {
3795fc9c5412SJohannes Schauer     gdbstub_port = atoi(arg);
3796fc9c5412SJohannes Schauer }
3797fc9c5412SJohannes Schauer 
3798fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
3799fc9c5412SJohannes Schauer {
3800fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
3801fc9c5412SJohannes Schauer }
3802fc9c5412SJohannes Schauer 
3803fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
3804fc9c5412SJohannes Schauer {
3805fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
3806c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
3807fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
3808e916cbf8SPeter Maydell #if defined(cpu_list)
3809e916cbf8SPeter Maydell         cpu_list(stdout, &fprintf);
3810fc9c5412SJohannes Schauer #endif
38114d1275c2SRiku Voipio         exit(EXIT_FAILURE);
3812fc9c5412SJohannes Schauer     }
3813fc9c5412SJohannes Schauer }
3814fc9c5412SJohannes Schauer 
3815fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
3816fc9c5412SJohannes Schauer {
3817fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
3818fc9c5412SJohannes Schauer     have_guest_base = 1;
3819fc9c5412SJohannes Schauer }
3820fc9c5412SJohannes Schauer 
3821fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
3822fc9c5412SJohannes Schauer {
3823fc9c5412SJohannes Schauer     char *p;
3824fc9c5412SJohannes Schauer     int shift = 0;
3825fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
3826fc9c5412SJohannes Schauer     switch (*p) {
3827fc9c5412SJohannes Schauer     case 'k':
3828fc9c5412SJohannes Schauer     case 'K':
3829fc9c5412SJohannes Schauer         shift = 10;
3830fc9c5412SJohannes Schauer         break;
3831fc9c5412SJohannes Schauer     case 'M':
3832fc9c5412SJohannes Schauer         shift = 20;
3833fc9c5412SJohannes Schauer         break;
3834fc9c5412SJohannes Schauer     case 'G':
3835fc9c5412SJohannes Schauer         shift = 30;
3836fc9c5412SJohannes Schauer         break;
3837fc9c5412SJohannes Schauer     }
3838fc9c5412SJohannes Schauer     if (shift) {
3839fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
3840fc9c5412SJohannes Schauer         p++;
3841fc9c5412SJohannes Schauer         reserved_va <<= shift;
3842fc9c5412SJohannes Schauer         if (((reserved_va >> shift) != unshifted)
3843fc9c5412SJohannes Schauer #if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
3844fc9c5412SJohannes Schauer             || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
3845fc9c5412SJohannes Schauer #endif
3846fc9c5412SJohannes Schauer             ) {
3847fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
38484d1275c2SRiku Voipio             exit(EXIT_FAILURE);
3849fc9c5412SJohannes Schauer         }
3850fc9c5412SJohannes Schauer     }
3851fc9c5412SJohannes Schauer     if (*p) {
3852fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
38534d1275c2SRiku Voipio         exit(EXIT_FAILURE);
3854fc9c5412SJohannes Schauer     }
3855fc9c5412SJohannes Schauer }
3856fc9c5412SJohannes Schauer 
3857fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
3858fc9c5412SJohannes Schauer {
3859fc9c5412SJohannes Schauer     singlestep = 1;
3860fc9c5412SJohannes Schauer }
3861fc9c5412SJohannes Schauer 
3862fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
3863fc9c5412SJohannes Schauer {
3864fc9c5412SJohannes Schauer     do_strace = 1;
3865fc9c5412SJohannes Schauer }
3866fc9c5412SJohannes Schauer 
3867fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
3868fc9c5412SJohannes Schauer {
38692e59915dSPaolo Bonzini     printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
3870fc9c5412SJohannes Schauer            ", Copyright (c) 2003-2008 Fabrice Bellard\n");
38714d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
3872fc9c5412SJohannes Schauer }
3873fc9c5412SJohannes Schauer 
3874fc9c5412SJohannes Schauer struct qemu_argument {
3875fc9c5412SJohannes Schauer     const char *argv;
3876fc9c5412SJohannes Schauer     const char *env;
3877fc9c5412SJohannes Schauer     bool has_arg;
3878fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
3879fc9c5412SJohannes Schauer     const char *example;
3880fc9c5412SJohannes Schauer     const char *help;
3881fc9c5412SJohannes Schauer };
3882fc9c5412SJohannes Schauer 
388342644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
3884fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
3885fc9c5412SJohannes Schauer      "",           "print this help"},
3886daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
3887daaf8c8eSMeador Inge      "",           ""},
3888fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
3889fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
3890fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
3891fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
3892fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
3893fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
3894fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
3895c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
3896fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
3897fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
3898fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
3899fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
3900fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
3901fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
3902fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
3903fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
3904fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
3905fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
3906fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
3907fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
3908fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
3909989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
3910989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
391150171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
3912989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
3913fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
3914fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
3915fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
3916fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
3917fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
3918fc9c5412SJohannes Schauer      "",           "log system calls"},
3919c5e4a5a9SMagnus Reftel     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_randseed,
3920c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
3921fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
39221386d4c0SPeter Maydell      "",           "display version information and exit"},
3923fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
3924fc9c5412SJohannes Schauer };
3925fc9c5412SJohannes Schauer 
3926d03f9c32SMeador Inge static void usage(int exitcode)
3927fc9c5412SJohannes Schauer {
392842644ceeSJim Meyering     const struct qemu_argument *arginfo;
3929fc9c5412SJohannes Schauer     int maxarglen;
3930fc9c5412SJohannes Schauer     int maxenvlen;
3931fc9c5412SJohannes Schauer 
39322e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
39332e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
3934fc9c5412SJohannes Schauer            "\n"
3935fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
3936fc9c5412SJohannes Schauer            "\n");
3937fc9c5412SJohannes Schauer 
393863ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
393963ec54d7SPeter Maydell      * for the column header.
394063ec54d7SPeter Maydell      */
394163ec54d7SPeter Maydell     maxarglen = strlen("Argument");
394263ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
3943fc9c5412SJohannes Schauer 
3944fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
394563ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
394663ec54d7SPeter Maydell         if (arginfo->has_arg) {
394763ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
394863ec54d7SPeter Maydell         }
3949fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
3950fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
3951fc9c5412SJohannes Schauer         }
395263ec54d7SPeter Maydell         if (arglen > maxarglen) {
395363ec54d7SPeter Maydell             maxarglen = arglen;
3954fc9c5412SJohannes Schauer         }
3955fc9c5412SJohannes Schauer     }
3956fc9c5412SJohannes Schauer 
395763ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
395863ec54d7SPeter Maydell             maxenvlen, "Env-variable");
3959fc9c5412SJohannes Schauer 
3960fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3961fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
3962fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
396363ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
396463ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
3965fc9c5412SJohannes Schauer         } else {
396663ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
3967fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
3968fc9c5412SJohannes Schauer                     arginfo->help);
3969fc9c5412SJohannes Schauer         }
3970fc9c5412SJohannes Schauer     }
3971fc9c5412SJohannes Schauer 
3972fc9c5412SJohannes Schauer     printf("\n"
3973fc9c5412SJohannes Schauer            "Defaults:\n"
3974fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
3975989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
3976fc9c5412SJohannes Schauer            interp_prefix,
3977989b697dSPeter Maydell            guest_stack_size);
3978fc9c5412SJohannes Schauer 
3979fc9c5412SJohannes Schauer     printf("\n"
3980fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
3981fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
3982fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
3983fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
3984fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
3985fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
3986fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
3987fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
3988fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
3989fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
3990fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
3991fc9c5412SJohannes Schauer            "the last change will stay in effect.\n");
3992fc9c5412SJohannes Schauer 
3993d03f9c32SMeador Inge     exit(exitcode);
3994fc9c5412SJohannes Schauer }
3995fc9c5412SJohannes Schauer 
3996fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
3997fc9c5412SJohannes Schauer {
3998fc9c5412SJohannes Schauer     const char *r;
3999fc9c5412SJohannes Schauer     int optind;
400042644ceeSJim Meyering     const struct qemu_argument *arginfo;
4001fc9c5412SJohannes Schauer 
4002fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
4003fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
4004fc9c5412SJohannes Schauer             continue;
4005fc9c5412SJohannes Schauer         }
4006fc9c5412SJohannes Schauer 
4007fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
4008fc9c5412SJohannes Schauer         if (r != NULL) {
4009fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
4010fc9c5412SJohannes Schauer         }
4011fc9c5412SJohannes Schauer     }
4012fc9c5412SJohannes Schauer 
4013fc9c5412SJohannes Schauer     optind = 1;
4014fc9c5412SJohannes Schauer     for (;;) {
4015fc9c5412SJohannes Schauer         if (optind >= argc) {
4016fc9c5412SJohannes Schauer             break;
4017fc9c5412SJohannes Schauer         }
4018fc9c5412SJohannes Schauer         r = argv[optind];
4019fc9c5412SJohannes Schauer         if (r[0] != '-') {
4020fc9c5412SJohannes Schauer             break;
4021fc9c5412SJohannes Schauer         }
4022fc9c5412SJohannes Schauer         optind++;
4023fc9c5412SJohannes Schauer         r++;
4024fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
4025fc9c5412SJohannes Schauer             break;
4026fc9c5412SJohannes Schauer         }
4027*ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
4028*ba02577cSMeador Inge         if (r[0] == '-') {
4029*ba02577cSMeador Inge             r++;
4030*ba02577cSMeador Inge         }
4031fc9c5412SJohannes Schauer 
4032fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
4033fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
40341386d4c0SPeter Maydell                 if (arginfo->has_arg) {
4035fc9c5412SJohannes Schauer                     if (optind >= argc) {
4036138940bfSMeador Inge                         (void) fprintf(stderr,
4037138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
40384d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
4039fc9c5412SJohannes Schauer                     }
4040fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
4041fc9c5412SJohannes Schauer                     optind++;
40421386d4c0SPeter Maydell                 } else {
40431386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
4044fc9c5412SJohannes Schauer                 }
4045fc9c5412SJohannes Schauer                 break;
4046fc9c5412SJohannes Schauer             }
4047fc9c5412SJohannes Schauer         }
4048fc9c5412SJohannes Schauer 
4049fc9c5412SJohannes Schauer         /* no option matched the current argv */
4050fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
4051138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
40524d1275c2SRiku Voipio             exit(EXIT_FAILURE);
4053fc9c5412SJohannes Schauer         }
4054fc9c5412SJohannes Schauer     }
4055fc9c5412SJohannes Schauer 
4056fc9c5412SJohannes Schauer     if (optind >= argc) {
4057138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
40584d1275c2SRiku Voipio         exit(EXIT_FAILURE);
4059fc9c5412SJohannes Schauer     }
4060fc9c5412SJohannes Schauer 
4061fc9c5412SJohannes Schauer     filename = argv[optind];
4062fc9c5412SJohannes Schauer     exec_path = argv[optind];
4063fc9c5412SJohannes Schauer 
4064fc9c5412SJohannes Schauer     return optind;
4065fc9c5412SJohannes Schauer }
4066fc9c5412SJohannes Schauer 
4067902b3d5cSmalc int main(int argc, char **argv, char **envp)
406831e31b8aSbellard {
406901ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
407031e31b8aSbellard     struct image_info info1, *info = &info1;
4071edf8e2afSMika Westerberg     struct linux_binprm bprm;
407248e15fc2SNathan Froyd     TaskState *ts;
40739349b4f9SAndreas Färber     CPUArchState *env;
4074db6b81d4SAndreas Färber     CPUState *cpu;
4075586314f2Sbellard     int optind;
407604a6dfebSaurel32     char **target_environ, **wrk;
40777d8cec95Saurel32     char **target_argv;
40787d8cec95Saurel32     int target_argc;
40797d8cec95Saurel32     int i;
4080fd4d81ddSArnaud Patard     int ret;
408103cfd8faSLaurent Vivier     int execfd;
408231e31b8aSbellard 
4083ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
4084ce008c1fSAndreas Färber 
408504a6dfebSaurel32     if ((envlist = envlist_create()) == NULL) {
408604a6dfebSaurel32         (void) fprintf(stderr, "Unable to allocate envlist\n");
40874d1275c2SRiku Voipio         exit(EXIT_FAILURE);
408804a6dfebSaurel32     }
408904a6dfebSaurel32 
409004a6dfebSaurel32     /* add current environment into the list */
409104a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
409204a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
409304a6dfebSaurel32     }
409404a6dfebSaurel32 
4095703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
4096703e0e89SRichard Henderson        then we can do little else besides use the default.  */
4097703e0e89SRichard Henderson     {
4098703e0e89SRichard Henderson         struct rlimit lim;
4099703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
410081bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
410181bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur == (target_long)lim.rlim_cur) {
4102703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
4103703e0e89SRichard Henderson         }
4104703e0e89SRichard Henderson     }
4105703e0e89SRichard Henderson 
4106b1f9be31Sj_mayer     cpu_model = NULL;
4107b5ec5ce0Sjohn cooper #if defined(cpudef_setup)
4108b5ec5ce0Sjohn cooper     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
4109b5ec5ce0Sjohn cooper #endif
4110b5ec5ce0Sjohn cooper 
4111c5e4a5a9SMagnus Reftel     srand(time(NULL));
4112c5e4a5a9SMagnus Reftel 
4113fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
41144b5dfd82SPeter Maydell 
411531e31b8aSbellard     /* Zero out regs */
411601ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
411731e31b8aSbellard 
411831e31b8aSbellard     /* Zero out image_info */
411931e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
412031e31b8aSbellard 
4121edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
4122edf8e2afSMika Westerberg 
412374cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
412474cd30b8Sbellard     init_paths(interp_prefix);
412574cd30b8Sbellard 
41264a24a758SPeter Maydell     init_qemu_uname_release();
41274a24a758SPeter Maydell 
412846027c07Sbellard     if (cpu_model == NULL) {
4129aaed909aSbellard #if defined(TARGET_I386)
413046027c07Sbellard #ifdef TARGET_X86_64
413146027c07Sbellard         cpu_model = "qemu64";
413246027c07Sbellard #else
413346027c07Sbellard         cpu_model = "qemu32";
413446027c07Sbellard #endif
4135aaed909aSbellard #elif defined(TARGET_ARM)
4136088ab16cSpbrook         cpu_model = "any";
4137d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
4138d2fbca94SGuan Xuetao         cpu_model = "any";
4139aaed909aSbellard #elif defined(TARGET_M68K)
4140aaed909aSbellard         cpu_model = "any";
4141aaed909aSbellard #elif defined(TARGET_SPARC)
4142aaed909aSbellard #ifdef TARGET_SPARC64
4143aaed909aSbellard         cpu_model = "TI UltraSparc II";
4144aaed909aSbellard #else
4145aaed909aSbellard         cpu_model = "Fujitsu MB86904";
414646027c07Sbellard #endif
4147aaed909aSbellard #elif defined(TARGET_MIPS)
4148aaed909aSbellard #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
414974797f40SMaciej W. Rozycki         cpu_model = "5KEf";
4150aaed909aSbellard #else
4151aaed909aSbellard         cpu_model = "24Kf";
4152aaed909aSbellard #endif
4153d962783eSJia Liu #elif defined TARGET_OPENRISC
4154d962783eSJia Liu         cpu_model = "or1200";
4155aaed909aSbellard #elif defined(TARGET_PPC)
41567ded4f52Sbellard # ifdef TARGET_PPC64
4157a74029f6SRichard Henderson         cpu_model = "POWER7";
41587ded4f52Sbellard # else
4159aaed909aSbellard         cpu_model = "750";
41607ded4f52Sbellard # endif
416191c45a38SRichard Henderson #elif defined TARGET_SH4
416291c45a38SRichard Henderson         cpu_model = TYPE_SH7785_CPU;
4163aaed909aSbellard #else
4164aaed909aSbellard         cpu_model = "any";
4165aaed909aSbellard #endif
4166aaed909aSbellard     }
4167d5ab9713SJan Kiszka     tcg_exec_init(0);
416883fb7adfSbellard     /* NOTE: we need to init the CPU at this stage to get
416983fb7adfSbellard        qemu_host_page_size */
41702994fd96SEduardo Habkost     cpu = cpu_init(cpu_model);
41712994fd96SEduardo Habkost     if (!cpu) {
4172aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
41734d1275c2SRiku Voipio         exit(EXIT_FAILURE);
4174aaed909aSbellard     }
41752994fd96SEduardo Habkost     env = cpu->env_ptr;
41760ac46af3SAndreas Färber     cpu_reset(cpu);
4177b55a37c9SBlue Swirl 
4178db6b81d4SAndreas Färber     thread_cpu = cpu;
417954936004Sbellard 
4180b92c47c1Sths     if (getenv("QEMU_STRACE")) {
4181b92c47c1Sths         do_strace = 1;
4182b92c47c1Sths     }
4183b92c47c1Sths 
4184c5e4a5a9SMagnus Reftel     if (getenv("QEMU_RAND_SEED")) {
4185c5e4a5a9SMagnus Reftel         handle_arg_randseed(getenv("QEMU_RAND_SEED"));
4186c5e4a5a9SMagnus Reftel     }
4187c5e4a5a9SMagnus Reftel 
418804a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
418904a6dfebSaurel32     envlist_free(envlist);
4190b12b6a18Sths 
4191379f6698SPaul Brook     /*
4192379f6698SPaul Brook      * Now that page sizes are configured in cpu_init() we can do
4193379f6698SPaul Brook      * proper page alignment for guest_base.
4194379f6698SPaul Brook      */
4195379f6698SPaul Brook     guest_base = HOST_PAGE_ALIGN(guest_base);
419668a1c816SPaul Brook 
419797cc7560SDr. David Alan Gilbert     if (reserved_va || have_guest_base) {
4198806d1021SMeador Inge         guest_base = init_guest_space(guest_base, reserved_va, 0,
4199806d1021SMeador Inge                                       have_guest_base);
4200806d1021SMeador Inge         if (guest_base == (unsigned long)-1) {
4201097b8cb8SPeter Maydell             fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address "
4202097b8cb8SPeter Maydell                     "space for use as guest address space (check your virtual "
4203097b8cb8SPeter Maydell                     "memory ulimit setting or reserve less using -R option)\n",
4204097b8cb8SPeter Maydell                     reserved_va);
42054d1275c2SRiku Voipio             exit(EXIT_FAILURE);
420697cc7560SDr. David Alan Gilbert         }
4207806d1021SMeador Inge 
4208806d1021SMeador Inge         if (reserved_va) {
4209806d1021SMeador Inge             mmap_next_start = reserved_va;
4210806d1021SMeador Inge         }
421197cc7560SDr. David Alan Gilbert     }
4212379f6698SPaul Brook 
4213379f6698SPaul Brook     /*
4214379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
4215379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
421614f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
4217379f6698SPaul Brook      */
421814f24e14SRichard Henderson     {
4219379f6698SPaul Brook         FILE *fp;
4220379f6698SPaul Brook 
4221379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
4222379f6698SPaul Brook             unsigned long tmp;
4223379f6698SPaul Brook             if (fscanf(fp, "%lu", &tmp) == 1) {
4224379f6698SPaul Brook                 mmap_min_addr = tmp;
4225379f6698SPaul Brook                 qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
4226379f6698SPaul Brook             }
4227379f6698SPaul Brook             fclose(fp);
4228379f6698SPaul Brook         }
4229379f6698SPaul Brook     }
4230379f6698SPaul Brook 
42317d8cec95Saurel32     /*
42327d8cec95Saurel32      * Prepare copy of argv vector for target.
42337d8cec95Saurel32      */
42347d8cec95Saurel32     target_argc = argc - optind;
42357d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
42367d8cec95Saurel32     if (target_argv == NULL) {
42377d8cec95Saurel32 	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
42384d1275c2SRiku Voipio 	exit(EXIT_FAILURE);
42397d8cec95Saurel32     }
42407d8cec95Saurel32 
42417d8cec95Saurel32     /*
42427d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
42437d8cec95Saurel32      * argv[0] pointer with the given one.
42447d8cec95Saurel32      */
42457d8cec95Saurel32     i = 0;
42467d8cec95Saurel32     if (argv0 != NULL) {
42477d8cec95Saurel32         target_argv[i++] = strdup(argv0);
42487d8cec95Saurel32     }
42497d8cec95Saurel32     for (; i < target_argc; i++) {
42507d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
42517d8cec95Saurel32     }
42527d8cec95Saurel32     target_argv[target_argc] = NULL;
42537d8cec95Saurel32 
42547267c094SAnthony Liguori     ts = g_malloc0 (sizeof(TaskState));
4255edf8e2afSMika Westerberg     init_task_state(ts);
4256edf8e2afSMika Westerberg     /* build Task State */
4257edf8e2afSMika Westerberg     ts->info = info;
4258edf8e2afSMika Westerberg     ts->bprm = &bprm;
42590429a971SAndreas Färber     cpu->opaque = ts;
4260edf8e2afSMika Westerberg     task_settid(ts);
4261edf8e2afSMika Westerberg 
42620b959cf5SRichard Henderson     execfd = qemu_getauxval(AT_EXECFD);
42630b959cf5SRichard Henderson     if (execfd == 0) {
426403cfd8faSLaurent Vivier         execfd = open(filename, O_RDONLY);
426503cfd8faSLaurent Vivier         if (execfd < 0) {
42660b959cf5SRichard Henderson             printf("Error while loading %s: %s\n", filename, strerror(errno));
42674d1275c2SRiku Voipio             _exit(EXIT_FAILURE);
426803cfd8faSLaurent Vivier         }
42690b959cf5SRichard Henderson     }
427003cfd8faSLaurent Vivier 
427103cfd8faSLaurent Vivier     ret = loader_exec(execfd, filename, target_argv, target_environ, regs,
4272fd4d81ddSArnaud Patard         info, &bprm);
4273fd4d81ddSArnaud Patard     if (ret != 0) {
4274885c1d10SPeter Maydell         printf("Error while loading %s: %s\n", filename, strerror(-ret));
42754d1275c2SRiku Voipio         _exit(EXIT_FAILURE);
427631e31b8aSbellard     }
427731e31b8aSbellard 
4278b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
4279b12b6a18Sths         free(*wrk);
4280b12b6a18Sths     }
4281b12b6a18Sths 
4282b12b6a18Sths     free(target_environ);
4283b12b6a18Sths 
42842e77eac6Sblueswir1     if (qemu_log_enabled()) {
4285379f6698SPaul Brook         qemu_log("guest_base  0x%lx\n", guest_base);
428693fcfe39Saliguori         log_page_dump();
428754936004Sbellard 
428893fcfe39Saliguori         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
428993fcfe39Saliguori         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
429093fcfe39Saliguori         qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
42913d177870Sj_mayer                  info->start_code);
429293fcfe39Saliguori         qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
42933d177870Sj_mayer                  info->start_data);
429493fcfe39Saliguori         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
429593fcfe39Saliguori         qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
42963d177870Sj_mayer                  info->start_stack);
429793fcfe39Saliguori         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
429893fcfe39Saliguori         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
42992e77eac6Sblueswir1     }
430031e31b8aSbellard 
430153a5960aSpbrook     target_set_brk(info->brk);
430231e31b8aSbellard     syscall_init();
430366fb9763Sbellard     signal_init();
430431e31b8aSbellard 
43059002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
43069002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
43079002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
43089002ec79SRichard Henderson     tcg_prologue_init(&tcg_ctx);
43099002ec79SRichard Henderson 
4310b346ff46Sbellard #if defined(TARGET_I386)
43113802ce26Sbellard     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
4312b98dbc90SPaolo Bonzini     env->hflags |= HF_PE_MASK | HF_CPL_MASK;
43130514ef2fSEduardo Habkost     if (env->features[FEAT_1_EDX] & CPUID_SSE) {
43141bde465eSbellard         env->cr[4] |= CR4_OSFXSR_MASK;
43151bde465eSbellard         env->hflags |= HF_OSFXSR_MASK;
43161bde465eSbellard     }
4317d2fd1af7Sbellard #ifndef TARGET_ABI32
43184dbc422bSbellard     /* enable 64 bit mode if possible */
43190514ef2fSEduardo Habkost     if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
43204dbc422bSbellard         fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
43214d1275c2SRiku Voipio         exit(EXIT_FAILURE);
43224dbc422bSbellard     }
4323d2fd1af7Sbellard     env->cr[4] |= CR4_PAE_MASK;
43244dbc422bSbellard     env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
4325d2fd1af7Sbellard     env->hflags |= HF_LMA_MASK;
4326d2fd1af7Sbellard #endif
43273802ce26Sbellard 
4328415e561fSbellard     /* flags setup : we activate the IRQs by default as in user mode */
4329415e561fSbellard     env->eflags |= IF_MASK;
4330415e561fSbellard 
43316dbad63eSbellard     /* linux register setup */
4332d2fd1af7Sbellard #ifndef TARGET_ABI32
433384409ddbSj_mayer     env->regs[R_EAX] = regs->rax;
433484409ddbSj_mayer     env->regs[R_EBX] = regs->rbx;
433584409ddbSj_mayer     env->regs[R_ECX] = regs->rcx;
433684409ddbSj_mayer     env->regs[R_EDX] = regs->rdx;
433784409ddbSj_mayer     env->regs[R_ESI] = regs->rsi;
433884409ddbSj_mayer     env->regs[R_EDI] = regs->rdi;
433984409ddbSj_mayer     env->regs[R_EBP] = regs->rbp;
434084409ddbSj_mayer     env->regs[R_ESP] = regs->rsp;
434184409ddbSj_mayer     env->eip = regs->rip;
434284409ddbSj_mayer #else
43430ecfa993Sbellard     env->regs[R_EAX] = regs->eax;
43440ecfa993Sbellard     env->regs[R_EBX] = regs->ebx;
43450ecfa993Sbellard     env->regs[R_ECX] = regs->ecx;
43460ecfa993Sbellard     env->regs[R_EDX] = regs->edx;
43470ecfa993Sbellard     env->regs[R_ESI] = regs->esi;
43480ecfa993Sbellard     env->regs[R_EDI] = regs->edi;
43490ecfa993Sbellard     env->regs[R_EBP] = regs->ebp;
43500ecfa993Sbellard     env->regs[R_ESP] = regs->esp;
4351dab2ed99Sbellard     env->eip = regs->eip;
435284409ddbSj_mayer #endif
435331e31b8aSbellard 
4354f4beb510Sbellard     /* linux interrupt setup */
4355e441570fSbalrog #ifndef TARGET_ABI32
4356e441570fSbalrog     env->idt.limit = 511;
4357e441570fSbalrog #else
4358e441570fSbalrog     env->idt.limit = 255;
4359e441570fSbalrog #endif
4360e441570fSbalrog     env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
4361e441570fSbalrog                                 PROT_READ|PROT_WRITE,
4362e441570fSbalrog                                 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
4363e441570fSbalrog     idt_table = g2h(env->idt.base);
4364f4beb510Sbellard     set_idt(0, 0);
4365f4beb510Sbellard     set_idt(1, 0);
4366f4beb510Sbellard     set_idt(2, 0);
4367f4beb510Sbellard     set_idt(3, 3);
4368f4beb510Sbellard     set_idt(4, 3);
4369ec95da6cSbellard     set_idt(5, 0);
4370f4beb510Sbellard     set_idt(6, 0);
4371f4beb510Sbellard     set_idt(7, 0);
4372f4beb510Sbellard     set_idt(8, 0);
4373f4beb510Sbellard     set_idt(9, 0);
4374f4beb510Sbellard     set_idt(10, 0);
4375f4beb510Sbellard     set_idt(11, 0);
4376f4beb510Sbellard     set_idt(12, 0);
4377f4beb510Sbellard     set_idt(13, 0);
4378f4beb510Sbellard     set_idt(14, 0);
4379f4beb510Sbellard     set_idt(15, 0);
4380f4beb510Sbellard     set_idt(16, 0);
4381f4beb510Sbellard     set_idt(17, 0);
4382f4beb510Sbellard     set_idt(18, 0);
4383f4beb510Sbellard     set_idt(19, 0);
4384f4beb510Sbellard     set_idt(0x80, 3);
4385f4beb510Sbellard 
43866dbad63eSbellard     /* linux segment setup */
43878d18e893Sbellard     {
43888d18e893Sbellard         uint64_t *gdt_table;
4389e441570fSbalrog         env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
4390e441570fSbalrog                                     PROT_READ|PROT_WRITE,
4391e441570fSbalrog                                     MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
43928d18e893Sbellard         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
4393e441570fSbalrog         gdt_table = g2h(env->gdt.base);
4394d2fd1af7Sbellard #ifdef TARGET_ABI32
4395f4beb510Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
4396f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
4397f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
4398d2fd1af7Sbellard #else
4399d2fd1af7Sbellard         /* 64 bit code segment */
4400d2fd1af7Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
4401d2fd1af7Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
4402d2fd1af7Sbellard                  DESC_L_MASK |
4403d2fd1af7Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
4404d2fd1af7Sbellard #endif
4405f4beb510Sbellard         write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
4406f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
4407f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
44088d18e893Sbellard     }
44096dbad63eSbellard     cpu_x86_load_seg(env, R_CS, __USER_CS);
4410d2fd1af7Sbellard     cpu_x86_load_seg(env, R_SS, __USER_DS);
4411d2fd1af7Sbellard #ifdef TARGET_ABI32
44126dbad63eSbellard     cpu_x86_load_seg(env, R_DS, __USER_DS);
44136dbad63eSbellard     cpu_x86_load_seg(env, R_ES, __USER_DS);
44146dbad63eSbellard     cpu_x86_load_seg(env, R_FS, __USER_DS);
44156dbad63eSbellard     cpu_x86_load_seg(env, R_GS, __USER_DS);
4416d6eb40f6Sths     /* This hack makes Wine work... */
4417d6eb40f6Sths     env->segs[R_FS].selector = 0;
4418d2fd1af7Sbellard #else
4419d2fd1af7Sbellard     cpu_x86_load_seg(env, R_DS, 0);
4420d2fd1af7Sbellard     cpu_x86_load_seg(env, R_ES, 0);
4421d2fd1af7Sbellard     cpu_x86_load_seg(env, R_FS, 0);
4422d2fd1af7Sbellard     cpu_x86_load_seg(env, R_GS, 0);
4423d2fd1af7Sbellard #endif
442499033caeSAlexander Graf #elif defined(TARGET_AARCH64)
442599033caeSAlexander Graf     {
442699033caeSAlexander Graf         int i;
442799033caeSAlexander Graf 
442899033caeSAlexander Graf         if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
442999033caeSAlexander Graf             fprintf(stderr,
443099033caeSAlexander Graf                     "The selected ARM CPU does not support 64 bit mode\n");
44314d1275c2SRiku Voipio             exit(EXIT_FAILURE);
443299033caeSAlexander Graf         }
443399033caeSAlexander Graf 
443499033caeSAlexander Graf         for (i = 0; i < 31; i++) {
443599033caeSAlexander Graf             env->xregs[i] = regs->regs[i];
443699033caeSAlexander Graf         }
443799033caeSAlexander Graf         env->pc = regs->pc;
443899033caeSAlexander Graf         env->xregs[31] = regs->sp;
443999033caeSAlexander Graf     }
4440b346ff46Sbellard #elif defined(TARGET_ARM)
4441b346ff46Sbellard     {
4442b346ff46Sbellard         int i;
4443b5ff1b31Sbellard         cpsr_write(env, regs->uregs[16], 0xffffffff);
4444b346ff46Sbellard         for(i = 0; i < 16; i++) {
4445b346ff46Sbellard             env->regs[i] = regs->uregs[i];
4446b346ff46Sbellard         }
4447d8fd2954SPaul Brook         /* Enable BE8.  */
4448d8fd2954SPaul Brook         if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
4449d8fd2954SPaul Brook             && (info->elf_flags & EF_ARM_BE8)) {
4450d8fd2954SPaul Brook             env->bswap_code = 1;
4451d8fd2954SPaul Brook         }
4452b346ff46Sbellard     }
4453d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
4454d2fbca94SGuan Xuetao     {
4455d2fbca94SGuan Xuetao         int i;
4456d2fbca94SGuan Xuetao         cpu_asr_write(env, regs->uregs[32], 0xffffffff);
4457d2fbca94SGuan Xuetao         for (i = 0; i < 32; i++) {
4458d2fbca94SGuan Xuetao             env->regs[i] = regs->uregs[i];
4459d2fbca94SGuan Xuetao         }
4460d2fbca94SGuan Xuetao     }
446193ac68bcSbellard #elif defined(TARGET_SPARC)
4462060366c5Sbellard     {
4463060366c5Sbellard         int i;
4464060366c5Sbellard 	env->pc = regs->pc;
4465060366c5Sbellard 	env->npc = regs->npc;
4466060366c5Sbellard         env->y = regs->y;
4467060366c5Sbellard         for(i = 0; i < 8; i++)
4468060366c5Sbellard             env->gregs[i] = regs->u_regs[i];
4469060366c5Sbellard         for(i = 0; i < 8; i++)
4470060366c5Sbellard             env->regwptr[i] = regs->u_regs[i + 8];
4471060366c5Sbellard     }
447267867308Sbellard #elif defined(TARGET_PPC)
447367867308Sbellard     {
447467867308Sbellard         int i;
44753fc6c082Sbellard 
44760411a972Sj_mayer #if defined(TARGET_PPC64)
44770411a972Sj_mayer #if defined(TARGET_ABI32)
44780411a972Sj_mayer         env->msr &= ~((target_ulong)1 << MSR_SF);
4479e85e7c6eSj_mayer #else
44800411a972Sj_mayer         env->msr |= (target_ulong)1 << MSR_SF;
44810411a972Sj_mayer #endif
448284409ddbSj_mayer #endif
448367867308Sbellard         env->nip = regs->nip;
448467867308Sbellard         for(i = 0; i < 32; i++) {
448567867308Sbellard             env->gpr[i] = regs->gpr[i];
448667867308Sbellard         }
448767867308Sbellard     }
4488e6e5906bSpbrook #elif defined(TARGET_M68K)
4489e6e5906bSpbrook     {
4490e6e5906bSpbrook         env->pc = regs->pc;
4491e6e5906bSpbrook         env->dregs[0] = regs->d0;
4492e6e5906bSpbrook         env->dregs[1] = regs->d1;
4493e6e5906bSpbrook         env->dregs[2] = regs->d2;
4494e6e5906bSpbrook         env->dregs[3] = regs->d3;
4495e6e5906bSpbrook         env->dregs[4] = regs->d4;
4496e6e5906bSpbrook         env->dregs[5] = regs->d5;
4497e6e5906bSpbrook         env->dregs[6] = regs->d6;
4498e6e5906bSpbrook         env->dregs[7] = regs->d7;
4499e6e5906bSpbrook         env->aregs[0] = regs->a0;
4500e6e5906bSpbrook         env->aregs[1] = regs->a1;
4501e6e5906bSpbrook         env->aregs[2] = regs->a2;
4502e6e5906bSpbrook         env->aregs[3] = regs->a3;
4503e6e5906bSpbrook         env->aregs[4] = regs->a4;
4504e6e5906bSpbrook         env->aregs[5] = regs->a5;
4505e6e5906bSpbrook         env->aregs[6] = regs->a6;
4506e6e5906bSpbrook         env->aregs[7] = regs->usp;
4507e6e5906bSpbrook         env->sr = regs->sr;
4508e6e5906bSpbrook         ts->sim_syscalls = 1;
4509e6e5906bSpbrook     }
4510b779e29eSEdgar E. Iglesias #elif defined(TARGET_MICROBLAZE)
4511b779e29eSEdgar E. Iglesias     {
4512b779e29eSEdgar E. Iglesias         env->regs[0] = regs->r0;
4513b779e29eSEdgar E. Iglesias         env->regs[1] = regs->r1;
4514b779e29eSEdgar E. Iglesias         env->regs[2] = regs->r2;
4515b779e29eSEdgar E. Iglesias         env->regs[3] = regs->r3;
4516b779e29eSEdgar E. Iglesias         env->regs[4] = regs->r4;
4517b779e29eSEdgar E. Iglesias         env->regs[5] = regs->r5;
4518b779e29eSEdgar E. Iglesias         env->regs[6] = regs->r6;
4519b779e29eSEdgar E. Iglesias         env->regs[7] = regs->r7;
4520b779e29eSEdgar E. Iglesias         env->regs[8] = regs->r8;
4521b779e29eSEdgar E. Iglesias         env->regs[9] = regs->r9;
4522b779e29eSEdgar E. Iglesias         env->regs[10] = regs->r10;
4523b779e29eSEdgar E. Iglesias         env->regs[11] = regs->r11;
4524b779e29eSEdgar E. Iglesias         env->regs[12] = regs->r12;
4525b779e29eSEdgar E. Iglesias         env->regs[13] = regs->r13;
4526b779e29eSEdgar E. Iglesias         env->regs[14] = regs->r14;
4527b779e29eSEdgar E. Iglesias         env->regs[15] = regs->r15;
4528b779e29eSEdgar E. Iglesias         env->regs[16] = regs->r16;
4529b779e29eSEdgar E. Iglesias         env->regs[17] = regs->r17;
4530b779e29eSEdgar E. Iglesias         env->regs[18] = regs->r18;
4531b779e29eSEdgar E. Iglesias         env->regs[19] = regs->r19;
4532b779e29eSEdgar E. Iglesias         env->regs[20] = regs->r20;
4533b779e29eSEdgar E. Iglesias         env->regs[21] = regs->r21;
4534b779e29eSEdgar E. Iglesias         env->regs[22] = regs->r22;
4535b779e29eSEdgar E. Iglesias         env->regs[23] = regs->r23;
4536b779e29eSEdgar E. Iglesias         env->regs[24] = regs->r24;
4537b779e29eSEdgar E. Iglesias         env->regs[25] = regs->r25;
4538b779e29eSEdgar E. Iglesias         env->regs[26] = regs->r26;
4539b779e29eSEdgar E. Iglesias         env->regs[27] = regs->r27;
4540b779e29eSEdgar E. Iglesias         env->regs[28] = regs->r28;
4541b779e29eSEdgar E. Iglesias         env->regs[29] = regs->r29;
4542b779e29eSEdgar E. Iglesias         env->regs[30] = regs->r30;
4543b779e29eSEdgar E. Iglesias         env->regs[31] = regs->r31;
4544b779e29eSEdgar E. Iglesias         env->sregs[SR_PC] = regs->pc;
4545b779e29eSEdgar E. Iglesias     }
4546048f6b4dSbellard #elif defined(TARGET_MIPS)
4547048f6b4dSbellard     {
4548048f6b4dSbellard         int i;
4549048f6b4dSbellard 
4550048f6b4dSbellard         for(i = 0; i < 32; i++) {
4551b5dc7732Sths             env->active_tc.gpr[i] = regs->regs[i];
4552048f6b4dSbellard         }
45530fddbbf2SNathan Froyd         env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
45540fddbbf2SNathan Froyd         if (regs->cp0_epc & 1) {
45550fddbbf2SNathan Froyd             env->hflags |= MIPS_HFLAG_M16;
45560fddbbf2SNathan Froyd         }
4557048f6b4dSbellard     }
4558d962783eSJia Liu #elif defined(TARGET_OPENRISC)
4559d962783eSJia Liu     {
4560d962783eSJia Liu         int i;
4561d962783eSJia Liu 
4562d962783eSJia Liu         for (i = 0; i < 32; i++) {
4563d962783eSJia Liu             env->gpr[i] = regs->gpr[i];
4564d962783eSJia Liu         }
4565d962783eSJia Liu 
4566d962783eSJia Liu         env->sr = regs->sr;
4567d962783eSJia Liu         env->pc = regs->pc;
4568d962783eSJia Liu     }
4569fdf9b3e8Sbellard #elif defined(TARGET_SH4)
4570fdf9b3e8Sbellard     {
4571fdf9b3e8Sbellard         int i;
4572fdf9b3e8Sbellard 
4573fdf9b3e8Sbellard         for(i = 0; i < 16; i++) {
4574fdf9b3e8Sbellard             env->gregs[i] = regs->regs[i];
4575fdf9b3e8Sbellard         }
4576fdf9b3e8Sbellard         env->pc = regs->pc;
4577fdf9b3e8Sbellard     }
45787a3148a9Sj_mayer #elif defined(TARGET_ALPHA)
45797a3148a9Sj_mayer     {
45807a3148a9Sj_mayer         int i;
45817a3148a9Sj_mayer 
45827a3148a9Sj_mayer         for(i = 0; i < 28; i++) {
4583992f48a0Sblueswir1             env->ir[i] = ((abi_ulong *)regs)[i];
45847a3148a9Sj_mayer         }
4585dad081eeSRichard Henderson         env->ir[IR_SP] = regs->usp;
45867a3148a9Sj_mayer         env->pc = regs->pc;
45877a3148a9Sj_mayer     }
458848733d19Sths #elif defined(TARGET_CRIS)
458948733d19Sths     {
459048733d19Sths 	    env->regs[0] = regs->r0;
459148733d19Sths 	    env->regs[1] = regs->r1;
459248733d19Sths 	    env->regs[2] = regs->r2;
459348733d19Sths 	    env->regs[3] = regs->r3;
459448733d19Sths 	    env->regs[4] = regs->r4;
459548733d19Sths 	    env->regs[5] = regs->r5;
459648733d19Sths 	    env->regs[6] = regs->r6;
459748733d19Sths 	    env->regs[7] = regs->r7;
459848733d19Sths 	    env->regs[8] = regs->r8;
459948733d19Sths 	    env->regs[9] = regs->r9;
460048733d19Sths 	    env->regs[10] = regs->r10;
460148733d19Sths 	    env->regs[11] = regs->r11;
460248733d19Sths 	    env->regs[12] = regs->r12;
460348733d19Sths 	    env->regs[13] = regs->r13;
460448733d19Sths 	    env->regs[14] = info->start_stack;
460548733d19Sths 	    env->regs[15] = regs->acr;
460648733d19Sths 	    env->pc = regs->erp;
460748733d19Sths     }
4608a4c075f1SUlrich Hecht #elif defined(TARGET_S390X)
4609a4c075f1SUlrich Hecht     {
4610a4c075f1SUlrich Hecht             int i;
4611a4c075f1SUlrich Hecht             for (i = 0; i < 16; i++) {
4612a4c075f1SUlrich Hecht                 env->regs[i] = regs->gprs[i];
4613a4c075f1SUlrich Hecht             }
4614a4c075f1SUlrich Hecht             env->psw.mask = regs->psw.mask;
4615a4c075f1SUlrich Hecht             env->psw.addr = regs->psw.addr;
4616a4c075f1SUlrich Hecht     }
4617b16189b2SChen Gang #elif defined(TARGET_TILEGX)
4618b16189b2SChen Gang     {
4619b16189b2SChen Gang         int i;
4620b16189b2SChen Gang         for (i = 0; i < TILEGX_R_COUNT; i++) {
4621b16189b2SChen Gang             env->regs[i] = regs->regs[i];
4622b16189b2SChen Gang         }
4623b16189b2SChen Gang         for (i = 0; i < TILEGX_SPR_COUNT; i++) {
4624b16189b2SChen Gang             env->spregs[i] = 0;
4625b16189b2SChen Gang         }
4626b16189b2SChen Gang         env->pc = regs->pc;
4627b16189b2SChen Gang     }
4628b346ff46Sbellard #else
4629b346ff46Sbellard #error unsupported target CPU
4630b346ff46Sbellard #endif
463131e31b8aSbellard 
4632d2fbca94SGuan Xuetao #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
4633a87295e8Spbrook     ts->stack_base = info->start_stack;
4634a87295e8Spbrook     ts->heap_base = info->brk;
4635a87295e8Spbrook     /* This will be filled in on the first SYS_HEAPINFO call.  */
4636a87295e8Spbrook     ts->heap_limit = 0;
4637a87295e8Spbrook #endif
4638a87295e8Spbrook 
463974c33bedSbellard     if (gdbstub_port) {
4640ff7a981aSPeter Maydell         if (gdbserver_start(gdbstub_port) < 0) {
4641ff7a981aSPeter Maydell             fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
4642ff7a981aSPeter Maydell                     gdbstub_port);
46434d1275c2SRiku Voipio             exit(EXIT_FAILURE);
4644ff7a981aSPeter Maydell         }
4645db6b81d4SAndreas Färber         gdb_handlesig(cpu, 0);
46461fddef4bSbellard     }
46471b6b029eSbellard     cpu_loop(env);
46481b6b029eSbellard     /* never exits */
464931e31b8aSbellard     return 0;
465031e31b8aSbellard }
4651