xref: /qemu/linux-user/main.c (revision 885c1d10)
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"
31902b3d5cSmalc #include "cache-utils.h"
322b41f10eSBlue Swirl #include "cpu.h"
339002ec79SRichard Henderson #include "tcg.h"
3429e922b6SBlue Swirl #include "qemu-timer.h"
3504a6dfebSaurel32 #include "envlist.h"
36d8fd2954SPaul Brook #include "elf.h"
3704a6dfebSaurel32 
383ef693a0Sbellard #define DEBUG_LOGFILE "/tmp/qemu.log"
39586314f2Sbellard 
40d088d664Saurel32 char *exec_path;
41d088d664Saurel32 
421b530a6dSaurel32 int singlestep;
43fc9c5412SJohannes Schauer const char *filename;
44fc9c5412SJohannes Schauer const char *argv0;
45fc9c5412SJohannes Schauer int gdbstub_port;
46fc9c5412SJohannes Schauer envlist_t *envlist;
47fc9c5412SJohannes Schauer const char *cpu_model;
48379f6698SPaul Brook unsigned long mmap_min_addr;
4914f24e14SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE)
50379f6698SPaul Brook unsigned long guest_base;
51379f6698SPaul Brook int have_guest_base;
52288e65b9SAlexander Graf #if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
53288e65b9SAlexander Graf /*
54288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
55288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
56288e65b9SAlexander Graf  *
57288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
58288e65b9SAlexander Graf  * or anything else that QEMU maps.
59288e65b9SAlexander Graf  */
60288e65b9SAlexander Graf unsigned long reserved_va = 0xf7000000;
61288e65b9SAlexander Graf #else
6268a1c816SPaul Brook unsigned long reserved_va;
63379f6698SPaul Brook #endif
64288e65b9SAlexander Graf #endif
651b530a6dSaurel32 
66fc9c5412SJohannes Schauer static void usage(void);
67fc9c5412SJohannes Schauer 
687ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
69c5937220Spbrook const char *qemu_uname_release = CONFIG_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 
922f7bb878SJuan Quintela #if defined(CONFIG_USE_NPTL)
93d5975363Spbrook /***********************************************************/
94d5975363Spbrook /* Helper routines for implementing atomic operations.  */
95d5975363Spbrook 
96d5975363Spbrook /* To implement exclusive operations we force all cpus to syncronise.
97d5975363Spbrook    We don't require a full sync, only that no cpus are executing guest code.
98d5975363Spbrook    The alternative is to map target atomic ops onto host equivalents,
99d5975363Spbrook    which requires quite a lot of per host/target work.  */
100c2764719Spbrook static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
101d5975363Spbrook static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
102d5975363Spbrook static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
103d5975363Spbrook static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
104d5975363Spbrook static int pending_cpus;
105d5975363Spbrook 
106d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
107d5975363Spbrook void fork_start(void)
108d5975363Spbrook {
109d5975363Spbrook     pthread_mutex_lock(&tb_lock);
110d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
111d032d1b4SRiku Voipio     mmap_fork_start();
112d5975363Spbrook }
113d5975363Spbrook 
114d5975363Spbrook void fork_end(int child)
115d5975363Spbrook {
116d032d1b4SRiku Voipio     mmap_fork_end(child);
117d5975363Spbrook     if (child) {
118d5975363Spbrook         /* Child processes created by fork() only have a single thread.
119d5975363Spbrook            Discard information about the parent threads.  */
120d5975363Spbrook         first_cpu = thread_env;
121d5975363Spbrook         thread_env->next_cpu = NULL;
122d5975363Spbrook         pending_cpus = 0;
123d5975363Spbrook         pthread_mutex_init(&exclusive_lock, NULL);
124c2764719Spbrook         pthread_mutex_init(&cpu_list_mutex, NULL);
125d5975363Spbrook         pthread_cond_init(&exclusive_cond, NULL);
126d5975363Spbrook         pthread_cond_init(&exclusive_resume, NULL);
127d5975363Spbrook         pthread_mutex_init(&tb_lock, NULL);
1282b1319c8Saurel32         gdbserver_fork(thread_env);
129d5975363Spbrook     } else {
130d5975363Spbrook         pthread_mutex_unlock(&exclusive_lock);
131d5975363Spbrook         pthread_mutex_unlock(&tb_lock);
132d5975363Spbrook     }
133d5975363Spbrook }
134d5975363Spbrook 
135d5975363Spbrook /* Wait for pending exclusive operations to complete.  The exclusive lock
136d5975363Spbrook    must be held.  */
137d5975363Spbrook static inline void exclusive_idle(void)
138d5975363Spbrook {
139d5975363Spbrook     while (pending_cpus) {
140d5975363Spbrook         pthread_cond_wait(&exclusive_resume, &exclusive_lock);
141d5975363Spbrook     }
142d5975363Spbrook }
143d5975363Spbrook 
144d5975363Spbrook /* Start an exclusive operation.
145d5975363Spbrook    Must only be called from outside cpu_arm_exec.   */
146d5975363Spbrook static inline void start_exclusive(void)
147d5975363Spbrook {
1489349b4f9SAndreas Färber     CPUArchState *other;
149d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
150d5975363Spbrook     exclusive_idle();
151d5975363Spbrook 
152d5975363Spbrook     pending_cpus = 1;
153d5975363Spbrook     /* Make all other cpus stop executing.  */
154d5975363Spbrook     for (other = first_cpu; other; other = other->next_cpu) {
155d5975363Spbrook         if (other->running) {
156d5975363Spbrook             pending_cpus++;
1573098dba0Saurel32             cpu_exit(other);
158d5975363Spbrook         }
159d5975363Spbrook     }
160d5975363Spbrook     if (pending_cpus > 1) {
161d5975363Spbrook         pthread_cond_wait(&exclusive_cond, &exclusive_lock);
162d5975363Spbrook     }
163d5975363Spbrook }
164d5975363Spbrook 
165d5975363Spbrook /* Finish an exclusive operation.  */
166d5975363Spbrook static inline void end_exclusive(void)
167d5975363Spbrook {
168d5975363Spbrook     pending_cpus = 0;
169d5975363Spbrook     pthread_cond_broadcast(&exclusive_resume);
170d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
171d5975363Spbrook }
172d5975363Spbrook 
173d5975363Spbrook /* Wait for exclusive ops to finish, and begin cpu execution.  */
1749349b4f9SAndreas Färber static inline void cpu_exec_start(CPUArchState *env)
175d5975363Spbrook {
176d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
177d5975363Spbrook     exclusive_idle();
178d5975363Spbrook     env->running = 1;
179d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
180d5975363Spbrook }
181d5975363Spbrook 
182d5975363Spbrook /* Mark cpu as not executing, and release pending exclusive ops.  */
1839349b4f9SAndreas Färber static inline void cpu_exec_end(CPUArchState *env)
184d5975363Spbrook {
185d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
186d5975363Spbrook     env->running = 0;
187d5975363Spbrook     if (pending_cpus > 1) {
188d5975363Spbrook         pending_cpus--;
189d5975363Spbrook         if (pending_cpus == 1) {
190d5975363Spbrook             pthread_cond_signal(&exclusive_cond);
191d5975363Spbrook         }
192d5975363Spbrook     }
193d5975363Spbrook     exclusive_idle();
194d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
195d5975363Spbrook }
196c2764719Spbrook 
197c2764719Spbrook void cpu_list_lock(void)
198c2764719Spbrook {
199c2764719Spbrook     pthread_mutex_lock(&cpu_list_mutex);
200c2764719Spbrook }
201c2764719Spbrook 
202c2764719Spbrook void cpu_list_unlock(void)
203c2764719Spbrook {
204c2764719Spbrook     pthread_mutex_unlock(&cpu_list_mutex);
205c2764719Spbrook }
2062f7bb878SJuan Quintela #else /* if !CONFIG_USE_NPTL */
207d5975363Spbrook /* These are no-ops because we are not threadsafe.  */
2089349b4f9SAndreas Färber static inline void cpu_exec_start(CPUArchState *env)
209d5975363Spbrook {
210d5975363Spbrook }
211d5975363Spbrook 
2129349b4f9SAndreas Färber static inline void cpu_exec_end(CPUArchState *env)
213d5975363Spbrook {
214d5975363Spbrook }
215d5975363Spbrook 
216d5975363Spbrook static inline void start_exclusive(void)
217d5975363Spbrook {
218d5975363Spbrook }
219d5975363Spbrook 
220d5975363Spbrook static inline void end_exclusive(void)
221d5975363Spbrook {
222d5975363Spbrook }
223d5975363Spbrook 
224d5975363Spbrook void fork_start(void)
225d5975363Spbrook {
226d5975363Spbrook }
227d5975363Spbrook 
228d5975363Spbrook void fork_end(int child)
229d5975363Spbrook {
2302b1319c8Saurel32     if (child) {
2312b1319c8Saurel32         gdbserver_fork(thread_env);
2322b1319c8Saurel32     }
233d5975363Spbrook }
234c2764719Spbrook 
235c2764719Spbrook void cpu_list_lock(void)
236c2764719Spbrook {
237c2764719Spbrook }
238c2764719Spbrook 
239c2764719Spbrook void cpu_list_unlock(void)
240c2764719Spbrook {
241c2764719Spbrook }
242d5975363Spbrook #endif
243d5975363Spbrook 
244d5975363Spbrook 
245a541f297Sbellard #ifdef TARGET_I386
246a541f297Sbellard /***********************************************************/
247a541f297Sbellard /* CPUX86 core interface */
248a541f297Sbellard 
24905390248SAndreas Färber void cpu_smm_update(CPUX86State *env)
25002a1602eSbellard {
25102a1602eSbellard }
25202a1602eSbellard 
25328ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env)
25428ab0e2eSbellard {
25528ab0e2eSbellard     return cpu_get_real_ticks();
25628ab0e2eSbellard }
25728ab0e2eSbellard 
258f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
259f4beb510Sbellard                      int flags)
2606dbad63eSbellard {
261f4beb510Sbellard     unsigned int e1, e2;
26253a5960aSpbrook     uint32_t *p;
2636dbad63eSbellard     e1 = (addr << 16) | (limit & 0xffff);
2646dbad63eSbellard     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
265f4beb510Sbellard     e2 |= flags;
26653a5960aSpbrook     p = ptr;
267d538e8f5Smalc     p[0] = tswap32(e1);
268d538e8f5Smalc     p[1] = tswap32(e2);
269f4beb510Sbellard }
270f4beb510Sbellard 
271e441570fSbalrog static uint64_t *idt_table;
272eb38c52cSblueswir1 #ifdef TARGET_X86_64
273d2fd1af7Sbellard static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
274d2fd1af7Sbellard                        uint64_t addr, unsigned int sel)
275d2fd1af7Sbellard {
2764dbc422bSbellard     uint32_t *p, e1, e2;
277d2fd1af7Sbellard     e1 = (addr & 0xffff) | (sel << 16);
278d2fd1af7Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
279d2fd1af7Sbellard     p = ptr;
2804dbc422bSbellard     p[0] = tswap32(e1);
2814dbc422bSbellard     p[1] = tswap32(e2);
2824dbc422bSbellard     p[2] = tswap32(addr >> 32);
2834dbc422bSbellard     p[3] = 0;
284d2fd1af7Sbellard }
285d2fd1af7Sbellard /* only dpl matters as we do only user space emulation */
286d2fd1af7Sbellard static void set_idt(int n, unsigned int dpl)
287d2fd1af7Sbellard {
288d2fd1af7Sbellard     set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
289d2fd1af7Sbellard }
290d2fd1af7Sbellard #else
291f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
292d2fd1af7Sbellard                      uint32_t addr, unsigned int sel)
293f4beb510Sbellard {
2944dbc422bSbellard     uint32_t *p, e1, e2;
295f4beb510Sbellard     e1 = (addr & 0xffff) | (sel << 16);
296f4beb510Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
29753a5960aSpbrook     p = ptr;
2984dbc422bSbellard     p[0] = tswap32(e1);
2994dbc422bSbellard     p[1] = tswap32(e2);
3006dbad63eSbellard }
3016dbad63eSbellard 
302f4beb510Sbellard /* only dpl matters as we do only user space emulation */
303f4beb510Sbellard static void set_idt(int n, unsigned int dpl)
304f4beb510Sbellard {
305f4beb510Sbellard     set_gate(idt_table + n, 0, dpl, 0, 0);
306f4beb510Sbellard }
307d2fd1af7Sbellard #endif
30831e31b8aSbellard 
30989e957e7Sbellard void cpu_loop(CPUX86State *env)
310bc8a22ccSbellard {
311bc8a22ccSbellard     int trapnr;
312992f48a0Sblueswir1     abi_ulong pc;
313c227f099SAnthony Liguori     target_siginfo_t info;
314bc8a22ccSbellard 
315bc8a22ccSbellard     for(;;) {
316bc8a22ccSbellard         trapnr = cpu_x86_exec(env);
317bc8a22ccSbellard         switch(trapnr) {
318f4beb510Sbellard         case 0x80:
319d2fd1af7Sbellard             /* linux syscall from int $0x80 */
3201b6b029eSbellard             env->regs[R_EAX] = do_syscall(env,
3211b6b029eSbellard                                           env->regs[R_EAX],
3221b6b029eSbellard                                           env->regs[R_EBX],
3231b6b029eSbellard                                           env->regs[R_ECX],
3241b6b029eSbellard                                           env->regs[R_EDX],
3251b6b029eSbellard                                           env->regs[R_ESI],
3261b6b029eSbellard                                           env->regs[R_EDI],
3275945cfcbSPeter Maydell                                           env->regs[R_EBP],
3285945cfcbSPeter Maydell                                           0, 0);
329f4beb510Sbellard             break;
330d2fd1af7Sbellard #ifndef TARGET_ABI32
331d2fd1af7Sbellard         case EXCP_SYSCALL:
3325ba18547SStefan Weil             /* linux syscall from syscall instruction */
333d2fd1af7Sbellard             env->regs[R_EAX] = do_syscall(env,
334d2fd1af7Sbellard                                           env->regs[R_EAX],
335d2fd1af7Sbellard                                           env->regs[R_EDI],
336d2fd1af7Sbellard                                           env->regs[R_ESI],
337d2fd1af7Sbellard                                           env->regs[R_EDX],
338d2fd1af7Sbellard                                           env->regs[10],
339d2fd1af7Sbellard                                           env->regs[8],
3405945cfcbSPeter Maydell                                           env->regs[9],
3415945cfcbSPeter Maydell                                           0, 0);
342d2fd1af7Sbellard             env->eip = env->exception_next_eip;
343d2fd1af7Sbellard             break;
344d2fd1af7Sbellard #endif
345f4beb510Sbellard         case EXCP0B_NOSEG:
346f4beb510Sbellard         case EXCP0C_STACK:
347f4beb510Sbellard             info.si_signo = SIGBUS;
348f4beb510Sbellard             info.si_errno = 0;
349f4beb510Sbellard             info.si_code = TARGET_SI_KERNEL;
350f4beb510Sbellard             info._sifields._sigfault._addr = 0;
351624f7979Spbrook             queue_signal(env, info.si_signo, &info);
352f4beb510Sbellard             break;
353f4beb510Sbellard         case EXCP0D_GPF:
354d2fd1af7Sbellard             /* XXX: potential problem if ABI32 */
35584409ddbSj_mayer #ifndef TARGET_X86_64
356f4beb510Sbellard             if (env->eflags & VM_MASK) {
357f4beb510Sbellard                 handle_vm86_fault(env);
35884409ddbSj_mayer             } else
35984409ddbSj_mayer #endif
36084409ddbSj_mayer             {
3619de5e440Sbellard                 info.si_signo = SIGSEGV;
3629de5e440Sbellard                 info.si_errno = 0;
363b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
3649de5e440Sbellard                 info._sifields._sigfault._addr = 0;
365624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
3661b6b029eSbellard             }
3671b6b029eSbellard             break;
368b689bc57Sbellard         case EXCP0E_PAGE:
369b689bc57Sbellard             info.si_signo = SIGSEGV;
370b689bc57Sbellard             info.si_errno = 0;
371b689bc57Sbellard             if (!(env->error_code & 1))
372b689bc57Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
373b689bc57Sbellard             else
374b689bc57Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
375970a87a6Sbellard             info._sifields._sigfault._addr = env->cr[2];
376624f7979Spbrook             queue_signal(env, info.si_signo, &info);
377b689bc57Sbellard             break;
3789de5e440Sbellard         case EXCP00_DIVZ:
37984409ddbSj_mayer #ifndef TARGET_X86_64
380bc8a22ccSbellard             if (env->eflags & VM_MASK) {
381447db213Sbellard                 handle_vm86_trap(env, trapnr);
38284409ddbSj_mayer             } else
38384409ddbSj_mayer #endif
38484409ddbSj_mayer             {
3859de5e440Sbellard                 /* division by zero */
3869de5e440Sbellard                 info.si_signo = SIGFPE;
3879de5e440Sbellard                 info.si_errno = 0;
3889de5e440Sbellard                 info.si_code = TARGET_FPE_INTDIV;
3899de5e440Sbellard                 info._sifields._sigfault._addr = env->eip;
390624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
391bc8a22ccSbellard             }
3929de5e440Sbellard             break;
39301df040bSaliguori         case EXCP01_DB:
394447db213Sbellard         case EXCP03_INT3:
39584409ddbSj_mayer #ifndef TARGET_X86_64
396447db213Sbellard             if (env->eflags & VM_MASK) {
397447db213Sbellard                 handle_vm86_trap(env, trapnr);
39884409ddbSj_mayer             } else
39984409ddbSj_mayer #endif
40084409ddbSj_mayer             {
401447db213Sbellard                 info.si_signo = SIGTRAP;
402447db213Sbellard                 info.si_errno = 0;
40301df040bSaliguori                 if (trapnr == EXCP01_DB) {
404447db213Sbellard                     info.si_code = TARGET_TRAP_BRKPT;
405447db213Sbellard                     info._sifields._sigfault._addr = env->eip;
406447db213Sbellard                 } else {
407447db213Sbellard                     info.si_code = TARGET_SI_KERNEL;
408447db213Sbellard                     info._sifields._sigfault._addr = 0;
409447db213Sbellard                 }
410624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
411447db213Sbellard             }
412447db213Sbellard             break;
4139de5e440Sbellard         case EXCP04_INTO:
4149de5e440Sbellard         case EXCP05_BOUND:
41584409ddbSj_mayer #ifndef TARGET_X86_64
416bc8a22ccSbellard             if (env->eflags & VM_MASK) {
417447db213Sbellard                 handle_vm86_trap(env, trapnr);
41884409ddbSj_mayer             } else
41984409ddbSj_mayer #endif
42084409ddbSj_mayer             {
4219de5e440Sbellard                 info.si_signo = SIGSEGV;
4229de5e440Sbellard                 info.si_errno = 0;
423b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
4249de5e440Sbellard                 info._sifields._sigfault._addr = 0;
425624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
426bc8a22ccSbellard             }
4279de5e440Sbellard             break;
4289de5e440Sbellard         case EXCP06_ILLOP:
4299de5e440Sbellard             info.si_signo = SIGILL;
4309de5e440Sbellard             info.si_errno = 0;
4319de5e440Sbellard             info.si_code = TARGET_ILL_ILLOPN;
4329de5e440Sbellard             info._sifields._sigfault._addr = env->eip;
433624f7979Spbrook             queue_signal(env, info.si_signo, &info);
4349de5e440Sbellard             break;
4359de5e440Sbellard         case EXCP_INTERRUPT:
4369de5e440Sbellard             /* just indicate that signals should be handled asap */
4379de5e440Sbellard             break;
4381fddef4bSbellard         case EXCP_DEBUG:
4391fddef4bSbellard             {
4401fddef4bSbellard                 int sig;
4411fddef4bSbellard 
4421fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
4431fddef4bSbellard                 if (sig)
4441fddef4bSbellard                   {
4451fddef4bSbellard                     info.si_signo = sig;
4461fddef4bSbellard                     info.si_errno = 0;
4471fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
448624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
4491fddef4bSbellard                   }
4501fddef4bSbellard             }
4511fddef4bSbellard             break;
4521b6b029eSbellard         default:
453970a87a6Sbellard             pc = env->segs[R_CS].base + env->eip;
454bc8a22ccSbellard             fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
455bc8a22ccSbellard                     (long)pc, trapnr);
4561b6b029eSbellard             abort();
4571b6b029eSbellard         }
45866fb9763Sbellard         process_pending_signals(env);
4591b6b029eSbellard     }
4601b6b029eSbellard }
461b346ff46Sbellard #endif
462b346ff46Sbellard 
463b346ff46Sbellard #ifdef TARGET_ARM
464b346ff46Sbellard 
465d8fd2954SPaul Brook #define get_user_code_u32(x, gaddr, doswap)             \
466d8fd2954SPaul Brook     ({ abi_long __r = get_user_u32((x), (gaddr));       \
467d8fd2954SPaul Brook         if (!__r && (doswap)) {                         \
468d8fd2954SPaul Brook             (x) = bswap32(x);                           \
469d8fd2954SPaul Brook         }                                               \
470d8fd2954SPaul Brook         __r;                                            \
471d8fd2954SPaul Brook     })
472d8fd2954SPaul Brook 
473d8fd2954SPaul Brook #define get_user_code_u16(x, gaddr, doswap)             \
474d8fd2954SPaul Brook     ({ abi_long __r = get_user_u16((x), (gaddr));       \
475d8fd2954SPaul Brook         if (!__r && (doswap)) {                         \
476d8fd2954SPaul Brook             (x) = bswap16(x);                           \
477d8fd2954SPaul Brook         }                                               \
478d8fd2954SPaul Brook         __r;                                            \
479d8fd2954SPaul Brook     })
480d8fd2954SPaul Brook 
48197cc7560SDr. David Alan Gilbert /*
48297cc7560SDr. David Alan Gilbert  * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
48397cc7560SDr. David Alan Gilbert  * Input:
48497cc7560SDr. David Alan Gilbert  * r0 = pointer to oldval
48597cc7560SDr. David Alan Gilbert  * r1 = pointer to newval
48697cc7560SDr. David Alan Gilbert  * r2 = pointer to target value
48797cc7560SDr. David Alan Gilbert  *
48897cc7560SDr. David Alan Gilbert  * Output:
48997cc7560SDr. David Alan Gilbert  * r0 = 0 if *ptr was changed, non-0 if no exchange happened
49097cc7560SDr. David Alan Gilbert  * C set if *ptr was changed, clear if no exchange happened
49197cc7560SDr. David Alan Gilbert  *
49297cc7560SDr. David Alan Gilbert  * Note segv's in kernel helpers are a bit tricky, we can set the
49397cc7560SDr. David Alan Gilbert  * data address sensibly but the PC address is just the entry point.
49497cc7560SDr. David Alan Gilbert  */
49597cc7560SDr. David Alan Gilbert static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
49697cc7560SDr. David Alan Gilbert {
49797cc7560SDr. David Alan Gilbert     uint64_t oldval, newval, val;
49897cc7560SDr. David Alan Gilbert     uint32_t addr, cpsr;
49997cc7560SDr. David Alan Gilbert     target_siginfo_t info;
50097cc7560SDr. David Alan Gilbert 
50197cc7560SDr. David Alan Gilbert     /* Based on the 32 bit code in do_kernel_trap */
50297cc7560SDr. David Alan Gilbert 
50397cc7560SDr. David Alan Gilbert     /* XXX: This only works between threads, not between processes.
50497cc7560SDr. David Alan Gilbert        It's probably possible to implement this with native host
50597cc7560SDr. David Alan Gilbert        operations. However things like ldrex/strex are much harder so
50697cc7560SDr. David Alan Gilbert        there's not much point trying.  */
50797cc7560SDr. David Alan Gilbert     start_exclusive();
50897cc7560SDr. David Alan Gilbert     cpsr = cpsr_read(env);
50997cc7560SDr. David Alan Gilbert     addr = env->regs[2];
51097cc7560SDr. David Alan Gilbert 
51197cc7560SDr. David Alan Gilbert     if (get_user_u64(oldval, env->regs[0])) {
51297cc7560SDr. David Alan Gilbert         env->cp15.c6_data = env->regs[0];
51397cc7560SDr. David Alan Gilbert         goto segv;
51497cc7560SDr. David Alan Gilbert     };
51597cc7560SDr. David Alan Gilbert 
51697cc7560SDr. David Alan Gilbert     if (get_user_u64(newval, env->regs[1])) {
51797cc7560SDr. David Alan Gilbert         env->cp15.c6_data = env->regs[1];
51897cc7560SDr. David Alan Gilbert         goto segv;
51997cc7560SDr. David Alan Gilbert     };
52097cc7560SDr. David Alan Gilbert 
52197cc7560SDr. David Alan Gilbert     if (get_user_u64(val, addr)) {
52297cc7560SDr. David Alan Gilbert         env->cp15.c6_data = addr;
52397cc7560SDr. David Alan Gilbert         goto segv;
52497cc7560SDr. David Alan Gilbert     }
52597cc7560SDr. David Alan Gilbert 
52697cc7560SDr. David Alan Gilbert     if (val == oldval) {
52797cc7560SDr. David Alan Gilbert         val = newval;
52897cc7560SDr. David Alan Gilbert 
52997cc7560SDr. David Alan Gilbert         if (put_user_u64(val, addr)) {
53097cc7560SDr. David Alan Gilbert             env->cp15.c6_data = addr;
53197cc7560SDr. David Alan Gilbert             goto segv;
53297cc7560SDr. David Alan Gilbert         };
53397cc7560SDr. David Alan Gilbert 
53497cc7560SDr. David Alan Gilbert         env->regs[0] = 0;
53597cc7560SDr. David Alan Gilbert         cpsr |= CPSR_C;
53697cc7560SDr. David Alan Gilbert     } else {
53797cc7560SDr. David Alan Gilbert         env->regs[0] = -1;
53897cc7560SDr. David Alan Gilbert         cpsr &= ~CPSR_C;
53997cc7560SDr. David Alan Gilbert     }
54097cc7560SDr. David Alan Gilbert     cpsr_write(env, cpsr, CPSR_C);
54197cc7560SDr. David Alan Gilbert     end_exclusive();
54297cc7560SDr. David Alan Gilbert     return;
54397cc7560SDr. David Alan Gilbert 
54497cc7560SDr. David Alan Gilbert segv:
54597cc7560SDr. David Alan Gilbert     end_exclusive();
54697cc7560SDr. David Alan Gilbert     /* We get the PC of the entry address - which is as good as anything,
54797cc7560SDr. David Alan Gilbert        on a real kernel what you get depends on which mode it uses. */
54897cc7560SDr. David Alan Gilbert     info.si_signo = SIGSEGV;
54997cc7560SDr. David Alan Gilbert     info.si_errno = 0;
55097cc7560SDr. David Alan Gilbert     /* XXX: check env->error_code */
55197cc7560SDr. David Alan Gilbert     info.si_code = TARGET_SEGV_MAPERR;
55297cc7560SDr. David Alan Gilbert     info._sifields._sigfault._addr = env->cp15.c6_data;
55397cc7560SDr. David Alan Gilbert     queue_signal(env, info.si_signo, &info);
55497cc7560SDr. David Alan Gilbert 
55597cc7560SDr. David Alan Gilbert     end_exclusive();
55697cc7560SDr. David Alan Gilbert }
55797cc7560SDr. David Alan Gilbert 
558fbb4a2e3Spbrook /* Handle a jump to the kernel code page.  */
559fbb4a2e3Spbrook static int
560fbb4a2e3Spbrook do_kernel_trap(CPUARMState *env)
561fbb4a2e3Spbrook {
562fbb4a2e3Spbrook     uint32_t addr;
563fbb4a2e3Spbrook     uint32_t cpsr;
564fbb4a2e3Spbrook     uint32_t val;
565fbb4a2e3Spbrook 
566fbb4a2e3Spbrook     switch (env->regs[15]) {
567fbb4a2e3Spbrook     case 0xffff0fa0: /* __kernel_memory_barrier */
568fbb4a2e3Spbrook         /* ??? No-op. Will need to do better for SMP.  */
569fbb4a2e3Spbrook         break;
570fbb4a2e3Spbrook     case 0xffff0fc0: /* __kernel_cmpxchg */
571d5975363Spbrook          /* XXX: This only works between threads, not between processes.
572d5975363Spbrook             It's probably possible to implement this with native host
573d5975363Spbrook             operations. However things like ldrex/strex are much harder so
574d5975363Spbrook             there's not much point trying.  */
575d5975363Spbrook         start_exclusive();
576fbb4a2e3Spbrook         cpsr = cpsr_read(env);
577fbb4a2e3Spbrook         addr = env->regs[2];
578fbb4a2e3Spbrook         /* FIXME: This should SEGV if the access fails.  */
579fbb4a2e3Spbrook         if (get_user_u32(val, addr))
580fbb4a2e3Spbrook             val = ~env->regs[0];
581fbb4a2e3Spbrook         if (val == env->regs[0]) {
582fbb4a2e3Spbrook             val = env->regs[1];
583fbb4a2e3Spbrook             /* FIXME: Check for segfaults.  */
584fbb4a2e3Spbrook             put_user_u32(val, addr);
585fbb4a2e3Spbrook             env->regs[0] = 0;
586fbb4a2e3Spbrook             cpsr |= CPSR_C;
587fbb4a2e3Spbrook         } else {
588fbb4a2e3Spbrook             env->regs[0] = -1;
589fbb4a2e3Spbrook             cpsr &= ~CPSR_C;
590fbb4a2e3Spbrook         }
591fbb4a2e3Spbrook         cpsr_write(env, cpsr, CPSR_C);
592d5975363Spbrook         end_exclusive();
593fbb4a2e3Spbrook         break;
594fbb4a2e3Spbrook     case 0xffff0fe0: /* __kernel_get_tls */
595fbb4a2e3Spbrook         env->regs[0] = env->cp15.c13_tls2;
596fbb4a2e3Spbrook         break;
59797cc7560SDr. David Alan Gilbert     case 0xffff0f60: /* __kernel_cmpxchg64 */
59897cc7560SDr. David Alan Gilbert         arm_kernel_cmpxchg64_helper(env);
59997cc7560SDr. David Alan Gilbert         break;
60097cc7560SDr. David Alan Gilbert 
601fbb4a2e3Spbrook     default:
602fbb4a2e3Spbrook         return 1;
603fbb4a2e3Spbrook     }
604fbb4a2e3Spbrook     /* Jump back to the caller.  */
605fbb4a2e3Spbrook     addr = env->regs[14];
606fbb4a2e3Spbrook     if (addr & 1) {
607fbb4a2e3Spbrook         env->thumb = 1;
608fbb4a2e3Spbrook         addr &= ~1;
609fbb4a2e3Spbrook     }
610fbb4a2e3Spbrook     env->regs[15] = addr;
611fbb4a2e3Spbrook 
612fbb4a2e3Spbrook     return 0;
613fbb4a2e3Spbrook }
614fbb4a2e3Spbrook 
615426f5abcSPaul Brook static int do_strex(CPUARMState *env)
616426f5abcSPaul Brook {
617426f5abcSPaul Brook     uint32_t val;
618426f5abcSPaul Brook     int size;
619426f5abcSPaul Brook     int rc = 1;
620426f5abcSPaul Brook     int segv = 0;
621426f5abcSPaul Brook     uint32_t addr;
622426f5abcSPaul Brook     start_exclusive();
623426f5abcSPaul Brook     addr = env->exclusive_addr;
624426f5abcSPaul Brook     if (addr != env->exclusive_test) {
625426f5abcSPaul Brook         goto fail;
626426f5abcSPaul Brook     }
627426f5abcSPaul Brook     size = env->exclusive_info & 0xf;
628426f5abcSPaul Brook     switch (size) {
629426f5abcSPaul Brook     case 0:
630426f5abcSPaul Brook         segv = get_user_u8(val, addr);
631426f5abcSPaul Brook         break;
632426f5abcSPaul Brook     case 1:
633426f5abcSPaul Brook         segv = get_user_u16(val, addr);
634426f5abcSPaul Brook         break;
635426f5abcSPaul Brook     case 2:
636426f5abcSPaul Brook     case 3:
637426f5abcSPaul Brook         segv = get_user_u32(val, addr);
638426f5abcSPaul Brook         break;
639f7001a3bSAurelien Jarno     default:
640f7001a3bSAurelien Jarno         abort();
641426f5abcSPaul Brook     }
642426f5abcSPaul Brook     if (segv) {
643426f5abcSPaul Brook         env->cp15.c6_data = addr;
644426f5abcSPaul Brook         goto done;
645426f5abcSPaul Brook     }
646426f5abcSPaul Brook     if (val != env->exclusive_val) {
647426f5abcSPaul Brook         goto fail;
648426f5abcSPaul Brook     }
649426f5abcSPaul Brook     if (size == 3) {
650426f5abcSPaul Brook         segv = get_user_u32(val, addr + 4);
651426f5abcSPaul Brook         if (segv) {
652426f5abcSPaul Brook             env->cp15.c6_data = addr + 4;
653426f5abcSPaul Brook             goto done;
654426f5abcSPaul Brook         }
655426f5abcSPaul Brook         if (val != env->exclusive_high) {
656426f5abcSPaul Brook             goto fail;
657426f5abcSPaul Brook         }
658426f5abcSPaul Brook     }
659426f5abcSPaul Brook     val = env->regs[(env->exclusive_info >> 8) & 0xf];
660426f5abcSPaul Brook     switch (size) {
661426f5abcSPaul Brook     case 0:
662426f5abcSPaul Brook         segv = put_user_u8(val, addr);
663426f5abcSPaul Brook         break;
664426f5abcSPaul Brook     case 1:
665426f5abcSPaul Brook         segv = put_user_u16(val, addr);
666426f5abcSPaul Brook         break;
667426f5abcSPaul Brook     case 2:
668426f5abcSPaul Brook     case 3:
669426f5abcSPaul Brook         segv = put_user_u32(val, addr);
670426f5abcSPaul Brook         break;
671426f5abcSPaul Brook     }
672426f5abcSPaul Brook     if (segv) {
673426f5abcSPaul Brook         env->cp15.c6_data = addr;
674426f5abcSPaul Brook         goto done;
675426f5abcSPaul Brook     }
676426f5abcSPaul Brook     if (size == 3) {
677426f5abcSPaul Brook         val = env->regs[(env->exclusive_info >> 12) & 0xf];
6782c9adbdaSPeter Maydell         segv = put_user_u32(val, addr + 4);
679426f5abcSPaul Brook         if (segv) {
680426f5abcSPaul Brook             env->cp15.c6_data = addr + 4;
681426f5abcSPaul Brook             goto done;
682426f5abcSPaul Brook         }
683426f5abcSPaul Brook     }
684426f5abcSPaul Brook     rc = 0;
685426f5abcSPaul Brook fail:
686725b8a69SPaul Brook     env->regs[15] += 4;
687426f5abcSPaul Brook     env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
688426f5abcSPaul Brook done:
689426f5abcSPaul Brook     end_exclusive();
690426f5abcSPaul Brook     return segv;
691426f5abcSPaul Brook }
692426f5abcSPaul Brook 
693b346ff46Sbellard void cpu_loop(CPUARMState *env)
694b346ff46Sbellard {
695b346ff46Sbellard     int trapnr;
696b346ff46Sbellard     unsigned int n, insn;
697c227f099SAnthony Liguori     target_siginfo_t info;
698b5ff1b31Sbellard     uint32_t addr;
699b346ff46Sbellard 
700b346ff46Sbellard     for(;;) {
701d5975363Spbrook         cpu_exec_start(env);
702b346ff46Sbellard         trapnr = cpu_arm_exec(env);
703d5975363Spbrook         cpu_exec_end(env);
704b346ff46Sbellard         switch(trapnr) {
705b346ff46Sbellard         case EXCP_UDEF:
706c6981055Sbellard             {
707c6981055Sbellard                 TaskState *ts = env->opaque;
708c6981055Sbellard                 uint32_t opcode;
7096d9a42beSaurel32                 int rc;
710c6981055Sbellard 
711c6981055Sbellard                 /* we handle the FPU emulation here, as Linux */
712c6981055Sbellard                 /* we get the opcode */
7132f619698Sbellard                 /* FIXME - what to do if get_user() fails? */
714d8fd2954SPaul Brook                 get_user_code_u32(opcode, env->regs[15], env->bswap_code);
715c6981055Sbellard 
7166d9a42beSaurel32                 rc = EmulateAll(opcode, &ts->fpa, env);
7176d9a42beSaurel32                 if (rc == 0) { /* illegal instruction */
718b346ff46Sbellard                     info.si_signo = SIGILL;
719b346ff46Sbellard                     info.si_errno = 0;
720b346ff46Sbellard                     info.si_code = TARGET_ILL_ILLOPN;
721b346ff46Sbellard                     info._sifields._sigfault._addr = env->regs[15];
722624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
7236d9a42beSaurel32                 } else if (rc < 0) { /* FP exception */
7246d9a42beSaurel32                     int arm_fpe=0;
7256d9a42beSaurel32 
7266d9a42beSaurel32                     /* translate softfloat flags to FPSR flags */
7276d9a42beSaurel32                     if (-rc & float_flag_invalid)
7286d9a42beSaurel32                       arm_fpe |= BIT_IOC;
7296d9a42beSaurel32                     if (-rc & float_flag_divbyzero)
7306d9a42beSaurel32                       arm_fpe |= BIT_DZC;
7316d9a42beSaurel32                     if (-rc & float_flag_overflow)
7326d9a42beSaurel32                       arm_fpe |= BIT_OFC;
7336d9a42beSaurel32                     if (-rc & float_flag_underflow)
7346d9a42beSaurel32                       arm_fpe |= BIT_UFC;
7356d9a42beSaurel32                     if (-rc & float_flag_inexact)
7366d9a42beSaurel32                       arm_fpe |= BIT_IXC;
7376d9a42beSaurel32 
7386d9a42beSaurel32                     FPSR fpsr = ts->fpa.fpsr;
7396d9a42beSaurel32                     //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
7406d9a42beSaurel32 
7416d9a42beSaurel32                     if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
7426d9a42beSaurel32                       info.si_signo = SIGFPE;
7436d9a42beSaurel32                       info.si_errno = 0;
7446d9a42beSaurel32 
7456d9a42beSaurel32                       /* ordered by priority, least first */
7466d9a42beSaurel32                       if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
7476d9a42beSaurel32                       if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
7486d9a42beSaurel32                       if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
7496d9a42beSaurel32                       if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
7506d9a42beSaurel32                       if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
7516d9a42beSaurel32 
7526d9a42beSaurel32                       info._sifields._sigfault._addr = env->regs[15];
753624f7979Spbrook                       queue_signal(env, info.si_signo, &info);
754c6981055Sbellard                     } else {
7556d9a42beSaurel32                       env->regs[15] += 4;
7566d9a42beSaurel32                     }
7576d9a42beSaurel32 
7586d9a42beSaurel32                     /* accumulate unenabled exceptions */
7596d9a42beSaurel32                     if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
7606d9a42beSaurel32                       fpsr |= BIT_IXC;
7616d9a42beSaurel32                     if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
7626d9a42beSaurel32                       fpsr |= BIT_UFC;
7636d9a42beSaurel32                     if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
7646d9a42beSaurel32                       fpsr |= BIT_OFC;
7656d9a42beSaurel32                     if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
7666d9a42beSaurel32                       fpsr |= BIT_DZC;
7676d9a42beSaurel32                     if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
7686d9a42beSaurel32                       fpsr |= BIT_IOC;
7696d9a42beSaurel32                     ts->fpa.fpsr=fpsr;
7706d9a42beSaurel32                 } else { /* everything OK */
771c6981055Sbellard                     /* increment PC */
772c6981055Sbellard                     env->regs[15] += 4;
773c6981055Sbellard                 }
774c6981055Sbellard             }
775b346ff46Sbellard             break;
776b346ff46Sbellard         case EXCP_SWI:
77706c949e6Spbrook         case EXCP_BKPT:
778b346ff46Sbellard             {
779ce4defa0Spbrook                 env->eabi = 1;
780b346ff46Sbellard                 /* system call */
78106c949e6Spbrook                 if (trapnr == EXCP_BKPT) {
78206c949e6Spbrook                     if (env->thumb) {
7832f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
784d8fd2954SPaul Brook                         get_user_code_u16(insn, env->regs[15], env->bswap_code);
78506c949e6Spbrook                         n = insn & 0xff;
78606c949e6Spbrook                         env->regs[15] += 2;
78706c949e6Spbrook                     } else {
7882f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
789d8fd2954SPaul Brook                         get_user_code_u32(insn, env->regs[15], env->bswap_code);
79006c949e6Spbrook                         n = (insn & 0xf) | ((insn >> 4) & 0xff0);
79106c949e6Spbrook                         env->regs[15] += 4;
79206c949e6Spbrook                     }
79306c949e6Spbrook                 } else {
794192c7bd9Sbellard                     if (env->thumb) {
7952f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
796d8fd2954SPaul Brook                         get_user_code_u16(insn, env->regs[15] - 2,
797d8fd2954SPaul Brook                                           env->bswap_code);
798192c7bd9Sbellard                         n = insn & 0xff;
799192c7bd9Sbellard                     } else {
8002f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
801d8fd2954SPaul Brook                         get_user_code_u32(insn, env->regs[15] - 4,
802d8fd2954SPaul Brook                                           env->bswap_code);
803b346ff46Sbellard                         n = insn & 0xffffff;
804192c7bd9Sbellard                     }
80506c949e6Spbrook                 }
806192c7bd9Sbellard 
8076f1f31c0Sbellard                 if (n == ARM_NR_cacheflush) {
808dcfd14b3SBlue Swirl                     /* nop */
809a4f81979Sbellard                 } else if (n == ARM_NR_semihosting
810a4f81979Sbellard                            || n == ARM_NR_thumb_semihosting) {
811a4f81979Sbellard                     env->regs[0] = do_arm_semihosting (env);
8123a1363acSAlexander Graf                 } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
813b346ff46Sbellard                     /* linux syscall */
814ce4defa0Spbrook                     if (env->thumb || n == 0) {
815192c7bd9Sbellard                         n = env->regs[7];
816192c7bd9Sbellard                     } else {
817b346ff46Sbellard                         n -= ARM_SYSCALL_BASE;
818ce4defa0Spbrook                         env->eabi = 0;
819192c7bd9Sbellard                     }
820fbb4a2e3Spbrook                     if ( n > ARM_NR_BASE) {
821fbb4a2e3Spbrook                         switch (n) {
822fbb4a2e3Spbrook                         case ARM_NR_cacheflush:
823dcfd14b3SBlue Swirl                             /* nop */
824fbb4a2e3Spbrook                             break;
825fbb4a2e3Spbrook                         case ARM_NR_set_tls:
826fbb4a2e3Spbrook                             cpu_set_tls(env, env->regs[0]);
827fbb4a2e3Spbrook                             env->regs[0] = 0;
828fbb4a2e3Spbrook                             break;
829fbb4a2e3Spbrook                         default:
830fbb4a2e3Spbrook                             gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
831fbb4a2e3Spbrook                                      n);
832fbb4a2e3Spbrook                             env->regs[0] = -TARGET_ENOSYS;
833fbb4a2e3Spbrook                             break;
834fbb4a2e3Spbrook                         }
835fbb4a2e3Spbrook                     } else {
836b346ff46Sbellard                         env->regs[0] = do_syscall(env,
837b346ff46Sbellard                                                   n,
838b346ff46Sbellard                                                   env->regs[0],
839b346ff46Sbellard                                                   env->regs[1],
840b346ff46Sbellard                                                   env->regs[2],
841b346ff46Sbellard                                                   env->regs[3],
842b346ff46Sbellard                                                   env->regs[4],
8435945cfcbSPeter Maydell                                                   env->regs[5],
8445945cfcbSPeter Maydell                                                   0, 0);
845fbb4a2e3Spbrook                     }
846b346ff46Sbellard                 } else {
847b346ff46Sbellard                     goto error;
848b346ff46Sbellard                 }
849b346ff46Sbellard             }
850b346ff46Sbellard             break;
85143fff238Sbellard         case EXCP_INTERRUPT:
85243fff238Sbellard             /* just indicate that signals should be handled asap */
85343fff238Sbellard             break;
85468016c62Sbellard         case EXCP_PREFETCH_ABORT:
855eae473c1Sbalrog             addr = env->cp15.c6_insn;
856b5ff1b31Sbellard             goto do_segv;
85768016c62Sbellard         case EXCP_DATA_ABORT:
858eae473c1Sbalrog             addr = env->cp15.c6_data;
859b5ff1b31Sbellard         do_segv:
86068016c62Sbellard             {
86168016c62Sbellard                 info.si_signo = SIGSEGV;
86268016c62Sbellard                 info.si_errno = 0;
86368016c62Sbellard                 /* XXX: check env->error_code */
86468016c62Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
865b5ff1b31Sbellard                 info._sifields._sigfault._addr = addr;
866624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
86768016c62Sbellard             }
86868016c62Sbellard             break;
8691fddef4bSbellard         case EXCP_DEBUG:
8701fddef4bSbellard             {
8711fddef4bSbellard                 int sig;
8721fddef4bSbellard 
8731fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
8741fddef4bSbellard                 if (sig)
8751fddef4bSbellard                   {
8761fddef4bSbellard                     info.si_signo = sig;
8771fddef4bSbellard                     info.si_errno = 0;
8781fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
879624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
8801fddef4bSbellard                   }
8811fddef4bSbellard             }
8821fddef4bSbellard             break;
883fbb4a2e3Spbrook         case EXCP_KERNEL_TRAP:
884fbb4a2e3Spbrook             if (do_kernel_trap(env))
885fbb4a2e3Spbrook               goto error;
886fbb4a2e3Spbrook             break;
887426f5abcSPaul Brook         case EXCP_STREX:
888426f5abcSPaul Brook             if (do_strex(env)) {
889426f5abcSPaul Brook                 addr = env->cp15.c6_data;
890426f5abcSPaul Brook                 goto do_segv;
891426f5abcSPaul Brook             }
892e9273455SPaul Brook             break;
893b346ff46Sbellard         default:
894b346ff46Sbellard         error:
895b346ff46Sbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
896b346ff46Sbellard                     trapnr);
8977fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
898b346ff46Sbellard             abort();
899b346ff46Sbellard         }
900b346ff46Sbellard         process_pending_signals(env);
901b346ff46Sbellard     }
902b346ff46Sbellard }
903b346ff46Sbellard 
904b346ff46Sbellard #endif
9051b6b029eSbellard 
906d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32
907d2fbca94SGuan Xuetao 
90805390248SAndreas Färber void cpu_loop(CPUUniCore32State *env)
909d2fbca94SGuan Xuetao {
910d2fbca94SGuan Xuetao     int trapnr;
911d2fbca94SGuan Xuetao     unsigned int n, insn;
912d2fbca94SGuan Xuetao     target_siginfo_t info;
913d2fbca94SGuan Xuetao 
914d2fbca94SGuan Xuetao     for (;;) {
915d2fbca94SGuan Xuetao         cpu_exec_start(env);
916d2fbca94SGuan Xuetao         trapnr = uc32_cpu_exec(env);
917d2fbca94SGuan Xuetao         cpu_exec_end(env);
918d2fbca94SGuan Xuetao         switch (trapnr) {
919d2fbca94SGuan Xuetao         case UC32_EXCP_PRIV:
920d2fbca94SGuan Xuetao             {
921d2fbca94SGuan Xuetao                 /* system call */
922d2fbca94SGuan Xuetao                 get_user_u32(insn, env->regs[31] - 4);
923d2fbca94SGuan Xuetao                 n = insn & 0xffffff;
924d2fbca94SGuan Xuetao 
925d2fbca94SGuan Xuetao                 if (n >= UC32_SYSCALL_BASE) {
926d2fbca94SGuan Xuetao                     /* linux syscall */
927d2fbca94SGuan Xuetao                     n -= UC32_SYSCALL_BASE;
928d2fbca94SGuan Xuetao                     if (n == UC32_SYSCALL_NR_set_tls) {
929d2fbca94SGuan Xuetao                             cpu_set_tls(env, env->regs[0]);
930d2fbca94SGuan Xuetao                             env->regs[0] = 0;
931d2fbca94SGuan Xuetao                     } else {
932d2fbca94SGuan Xuetao                         env->regs[0] = do_syscall(env,
933d2fbca94SGuan Xuetao                                                   n,
934d2fbca94SGuan Xuetao                                                   env->regs[0],
935d2fbca94SGuan Xuetao                                                   env->regs[1],
936d2fbca94SGuan Xuetao                                                   env->regs[2],
937d2fbca94SGuan Xuetao                                                   env->regs[3],
938d2fbca94SGuan Xuetao                                                   env->regs[4],
9395945cfcbSPeter Maydell                                                   env->regs[5],
9405945cfcbSPeter Maydell                                                   0, 0);
941d2fbca94SGuan Xuetao                     }
942d2fbca94SGuan Xuetao                 } else {
943d2fbca94SGuan Xuetao                     goto error;
944d2fbca94SGuan Xuetao                 }
945d2fbca94SGuan Xuetao             }
946d2fbca94SGuan Xuetao             break;
947d48813ddSGuan Xuetao         case UC32_EXCP_DTRAP:
948d48813ddSGuan Xuetao         case UC32_EXCP_ITRAP:
949d2fbca94SGuan Xuetao             info.si_signo = SIGSEGV;
950d2fbca94SGuan Xuetao             info.si_errno = 0;
951d2fbca94SGuan Xuetao             /* XXX: check env->error_code */
952d2fbca94SGuan Xuetao             info.si_code = TARGET_SEGV_MAPERR;
953d2fbca94SGuan Xuetao             info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
954d2fbca94SGuan Xuetao             queue_signal(env, info.si_signo, &info);
955d2fbca94SGuan Xuetao             break;
956d2fbca94SGuan Xuetao         case EXCP_INTERRUPT:
957d2fbca94SGuan Xuetao             /* just indicate that signals should be handled asap */
958d2fbca94SGuan Xuetao             break;
959d2fbca94SGuan Xuetao         case EXCP_DEBUG:
960d2fbca94SGuan Xuetao             {
961d2fbca94SGuan Xuetao                 int sig;
962d2fbca94SGuan Xuetao 
963d2fbca94SGuan Xuetao                 sig = gdb_handlesig(env, TARGET_SIGTRAP);
964d2fbca94SGuan Xuetao                 if (sig) {
965d2fbca94SGuan Xuetao                     info.si_signo = sig;
966d2fbca94SGuan Xuetao                     info.si_errno = 0;
967d2fbca94SGuan Xuetao                     info.si_code = TARGET_TRAP_BRKPT;
968d2fbca94SGuan Xuetao                     queue_signal(env, info.si_signo, &info);
969d2fbca94SGuan Xuetao                 }
970d2fbca94SGuan Xuetao             }
971d2fbca94SGuan Xuetao             break;
972d2fbca94SGuan Xuetao         default:
973d2fbca94SGuan Xuetao             goto error;
974d2fbca94SGuan Xuetao         }
975d2fbca94SGuan Xuetao         process_pending_signals(env);
976d2fbca94SGuan Xuetao     }
977d2fbca94SGuan Xuetao 
978d2fbca94SGuan Xuetao error:
979d2fbca94SGuan Xuetao     fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
980d2fbca94SGuan Xuetao     cpu_dump_state(env, stderr, fprintf, 0);
981d2fbca94SGuan Xuetao     abort();
982d2fbca94SGuan Xuetao }
983d2fbca94SGuan Xuetao #endif
984d2fbca94SGuan Xuetao 
98593ac68bcSbellard #ifdef TARGET_SPARC
986ed23fbd9Sblueswir1 #define SPARC64_STACK_BIAS 2047
98793ac68bcSbellard 
988060366c5Sbellard //#define DEBUG_WIN
989060366c5Sbellard 
9902623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info
9912623cbafSbellard    can be found at http://www.sics.se/~psm/sparcstack.html */
992060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
993060366c5Sbellard {
9941a14026eSblueswir1     index = (index + cwp * 16) % (16 * env->nwindows);
995060366c5Sbellard     /* wrap handling : if cwp is on the last window, then we use the
996060366c5Sbellard        registers 'after' the end */
9971a14026eSblueswir1     if (index < 8 && env->cwp == env->nwindows - 1)
9981a14026eSblueswir1         index += 16 * env->nwindows;
999060366c5Sbellard     return index;
1000060366c5Sbellard }
1001060366c5Sbellard 
10022623cbafSbellard /* save the register window 'cwp1' */
10032623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1)
1004060366c5Sbellard {
10052623cbafSbellard     unsigned int i;
1006992f48a0Sblueswir1     abi_ulong sp_ptr;
1007060366c5Sbellard 
100853a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1009ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1010ed23fbd9Sblueswir1     if (sp_ptr & 3)
1011ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1012ed23fbd9Sblueswir1 #endif
1013060366c5Sbellard #if defined(DEBUG_WIN)
10142daf0284Sblueswir1     printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
10152daf0284Sblueswir1            sp_ptr, cwp1);
1016060366c5Sbellard #endif
10172623cbafSbellard     for(i = 0; i < 16; i++) {
10182f619698Sbellard         /* FIXME - what to do if put_user() fails? */
10192f619698Sbellard         put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1020992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
10212623cbafSbellard     }
1022060366c5Sbellard }
1023060366c5Sbellard 
1024060366c5Sbellard static void save_window(CPUSPARCState *env)
1025060366c5Sbellard {
10265ef54116Sbellard #ifndef TARGET_SPARC64
10272623cbafSbellard     unsigned int new_wim;
10281a14026eSblueswir1     new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
10291a14026eSblueswir1         ((1LL << env->nwindows) - 1);
10301a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10312623cbafSbellard     env->wim = new_wim;
10325ef54116Sbellard #else
10331a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10345ef54116Sbellard     env->cansave++;
10355ef54116Sbellard     env->canrestore--;
10365ef54116Sbellard #endif
1037060366c5Sbellard }
1038060366c5Sbellard 
1039060366c5Sbellard static void restore_window(CPUSPARCState *env)
1040060366c5Sbellard {
1041eda52953Sblueswir1 #ifndef TARGET_SPARC64
1042eda52953Sblueswir1     unsigned int new_wim;
1043eda52953Sblueswir1 #endif
1044eda52953Sblueswir1     unsigned int i, cwp1;
1045992f48a0Sblueswir1     abi_ulong sp_ptr;
1046060366c5Sbellard 
1047eda52953Sblueswir1 #ifndef TARGET_SPARC64
10481a14026eSblueswir1     new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
10491a14026eSblueswir1         ((1LL << env->nwindows) - 1);
1050eda52953Sblueswir1 #endif
1051060366c5Sbellard 
1052060366c5Sbellard     /* restore the invalid window */
10531a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
105453a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1055ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1056ed23fbd9Sblueswir1     if (sp_ptr & 3)
1057ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1058ed23fbd9Sblueswir1 #endif
1059060366c5Sbellard #if defined(DEBUG_WIN)
10602daf0284Sblueswir1     printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
10612daf0284Sblueswir1            sp_ptr, cwp1);
1062060366c5Sbellard #endif
10632623cbafSbellard     for(i = 0; i < 16; i++) {
10642f619698Sbellard         /* FIXME - what to do if get_user() fails? */
10652f619698Sbellard         get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1066992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
10672623cbafSbellard     }
10685ef54116Sbellard #ifdef TARGET_SPARC64
10695ef54116Sbellard     env->canrestore++;
10701a14026eSblueswir1     if (env->cleanwin < env->nwindows - 1)
10715ef54116Sbellard         env->cleanwin++;
10725ef54116Sbellard     env->cansave--;
1073eda52953Sblueswir1 #else
1074eda52953Sblueswir1     env->wim = new_wim;
10755ef54116Sbellard #endif
1076060366c5Sbellard }
1077060366c5Sbellard 
1078060366c5Sbellard static void flush_windows(CPUSPARCState *env)
1079060366c5Sbellard {
1080060366c5Sbellard     int offset, cwp1;
10812623cbafSbellard 
10822623cbafSbellard     offset = 1;
1083060366c5Sbellard     for(;;) {
1084060366c5Sbellard         /* if restore would invoke restore_window(), then we can stop */
10851a14026eSblueswir1         cwp1 = cpu_cwp_inc(env, env->cwp + offset);
1086eda52953Sblueswir1 #ifndef TARGET_SPARC64
1087060366c5Sbellard         if (env->wim & (1 << cwp1))
1088060366c5Sbellard             break;
1089eda52953Sblueswir1 #else
1090eda52953Sblueswir1         if (env->canrestore == 0)
1091eda52953Sblueswir1             break;
1092eda52953Sblueswir1         env->cansave++;
1093eda52953Sblueswir1         env->canrestore--;
1094eda52953Sblueswir1 #endif
10952623cbafSbellard         save_window_offset(env, cwp1);
1096060366c5Sbellard         offset++;
1097060366c5Sbellard     }
10981a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
1099eda52953Sblueswir1 #ifndef TARGET_SPARC64
1100eda52953Sblueswir1     /* set wim so that restore will reload the registers */
11012623cbafSbellard     env->wim = 1 << cwp1;
1102eda52953Sblueswir1 #endif
11032623cbafSbellard #if defined(DEBUG_WIN)
11042623cbafSbellard     printf("flush_windows: nb=%d\n", offset - 1);
110580a9d035Sbellard #endif
11062623cbafSbellard }
1107060366c5Sbellard 
110893ac68bcSbellard void cpu_loop (CPUSPARCState *env)
110993ac68bcSbellard {
11102cc20260SRichard Henderson     int trapnr;
11112cc20260SRichard Henderson     abi_long ret;
1112c227f099SAnthony Liguori     target_siginfo_t info;
111393ac68bcSbellard 
111493ac68bcSbellard     while (1) {
111593ac68bcSbellard         trapnr = cpu_sparc_exec (env);
111693ac68bcSbellard 
111793ac68bcSbellard         switch (trapnr) {
11185ef54116Sbellard #ifndef TARGET_SPARC64
1119060366c5Sbellard         case 0x88:
1120060366c5Sbellard         case 0x90:
11215ef54116Sbellard #else
1122cb33da57Sblueswir1         case 0x110:
11235ef54116Sbellard         case 0x16d:
11245ef54116Sbellard #endif
1125060366c5Sbellard             ret = do_syscall (env, env->gregs[1],
1126060366c5Sbellard                               env->regwptr[0], env->regwptr[1],
1127060366c5Sbellard                               env->regwptr[2], env->regwptr[3],
11285945cfcbSPeter Maydell                               env->regwptr[4], env->regwptr[5],
11295945cfcbSPeter Maydell                               0, 0);
11302cc20260SRichard Henderson             if ((abi_ulong)ret >= (abi_ulong)(-515)) {
1131992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
113227908725Sbellard                 env->xcc |= PSR_CARRY;
113327908725Sbellard #else
113493ac68bcSbellard                 env->psr |= PSR_CARRY;
113527908725Sbellard #endif
1136060366c5Sbellard                 ret = -ret;
1137060366c5Sbellard             } else {
1138992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
113927908725Sbellard                 env->xcc &= ~PSR_CARRY;
114027908725Sbellard #else
1141060366c5Sbellard                 env->psr &= ~PSR_CARRY;
114227908725Sbellard #endif
1143060366c5Sbellard             }
1144060366c5Sbellard             env->regwptr[0] = ret;
1145060366c5Sbellard             /* next instruction */
1146060366c5Sbellard             env->pc = env->npc;
1147060366c5Sbellard             env->npc = env->npc + 4;
1148060366c5Sbellard             break;
1149060366c5Sbellard         case 0x83: /* flush windows */
1150992f48a0Sblueswir1 #ifdef TARGET_ABI32
1151992f48a0Sblueswir1         case 0x103:
1152992f48a0Sblueswir1 #endif
11532623cbafSbellard             flush_windows(env);
1154060366c5Sbellard             /* next instruction */
1155060366c5Sbellard             env->pc = env->npc;
1156060366c5Sbellard             env->npc = env->npc + 4;
1157060366c5Sbellard             break;
11583475187dSbellard #ifndef TARGET_SPARC64
1159060366c5Sbellard         case TT_WIN_OVF: /* window overflow */
1160060366c5Sbellard             save_window(env);
1161060366c5Sbellard             break;
1162060366c5Sbellard         case TT_WIN_UNF: /* window underflow */
1163060366c5Sbellard             restore_window(env);
116493ac68bcSbellard             break;
116561ff6f58Sbellard         case TT_TFAULT:
116661ff6f58Sbellard         case TT_DFAULT:
116761ff6f58Sbellard             {
116859f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
116961ff6f58Sbellard                 info.si_errno = 0;
117061ff6f58Sbellard                 /* XXX: check env->error_code */
117161ff6f58Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
117261ff6f58Sbellard                 info._sifields._sigfault._addr = env->mmuregs[4];
1173624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
117461ff6f58Sbellard             }
117561ff6f58Sbellard             break;
11763475187dSbellard #else
11775ef54116Sbellard         case TT_SPILL: /* window overflow */
11785ef54116Sbellard             save_window(env);
11795ef54116Sbellard             break;
11805ef54116Sbellard         case TT_FILL: /* window underflow */
11815ef54116Sbellard             restore_window(env);
11825ef54116Sbellard             break;
11837f84a729Sblueswir1         case TT_TFAULT:
11847f84a729Sblueswir1         case TT_DFAULT:
11857f84a729Sblueswir1             {
118659f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
11877f84a729Sblueswir1                 info.si_errno = 0;
11887f84a729Sblueswir1                 /* XXX: check env->error_code */
11897f84a729Sblueswir1                 info.si_code = TARGET_SEGV_MAPERR;
11907f84a729Sblueswir1                 if (trapnr == TT_DFAULT)
11917f84a729Sblueswir1                     info._sifields._sigfault._addr = env->dmmuregs[4];
11927f84a729Sblueswir1                 else
11938194f35aSIgor Kovalenko                     info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
1194624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
11957f84a729Sblueswir1             }
11967f84a729Sblueswir1             break;
119727524dc3Sbellard #ifndef TARGET_ABI32
11985bfb56b2Sblueswir1         case 0x16e:
11995bfb56b2Sblueswir1             flush_windows(env);
12005bfb56b2Sblueswir1             sparc64_get_context(env);
12015bfb56b2Sblueswir1             break;
12025bfb56b2Sblueswir1         case 0x16f:
12035bfb56b2Sblueswir1             flush_windows(env);
12045bfb56b2Sblueswir1             sparc64_set_context(env);
12055bfb56b2Sblueswir1             break;
12063475187dSbellard #endif
120727524dc3Sbellard #endif
120848dc41ebSbellard         case EXCP_INTERRUPT:
120948dc41ebSbellard             /* just indicate that signals should be handled asap */
1210e80cfcfcSbellard             break;
121175f22e4eSRichard Henderson         case TT_ILL_INSN:
121275f22e4eSRichard Henderson             {
121375f22e4eSRichard Henderson                 info.si_signo = TARGET_SIGILL;
121475f22e4eSRichard Henderson                 info.si_errno = 0;
121575f22e4eSRichard Henderson                 info.si_code = TARGET_ILL_ILLOPC;
121675f22e4eSRichard Henderson                 info._sifields._sigfault._addr = env->pc;
121775f22e4eSRichard Henderson                 queue_signal(env, info.si_signo, &info);
121875f22e4eSRichard Henderson             }
121975f22e4eSRichard Henderson             break;
12201fddef4bSbellard         case EXCP_DEBUG:
12211fddef4bSbellard             {
12221fddef4bSbellard                 int sig;
12231fddef4bSbellard 
12241fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
12251fddef4bSbellard                 if (sig)
12261fddef4bSbellard                   {
12271fddef4bSbellard                     info.si_signo = sig;
12281fddef4bSbellard                     info.si_errno = 0;
12291fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
1230624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
12311fddef4bSbellard                   }
12321fddef4bSbellard             }
12331fddef4bSbellard             break;
123493ac68bcSbellard         default:
1235060366c5Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
12367fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
123793ac68bcSbellard             exit (1);
123893ac68bcSbellard         }
123993ac68bcSbellard         process_pending_signals (env);
124093ac68bcSbellard     }
124193ac68bcSbellard }
124293ac68bcSbellard 
124393ac68bcSbellard #endif
124493ac68bcSbellard 
124567867308Sbellard #ifdef TARGET_PPC
124605390248SAndreas Färber static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
12479fddaa0cSbellard {
12489fddaa0cSbellard     /* TO FIX */
12499fddaa0cSbellard     return 0;
12509fddaa0cSbellard }
12519fddaa0cSbellard 
125205390248SAndreas Färber uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
12539fddaa0cSbellard {
1254e3ea6529SAlexander Graf     return cpu_ppc_get_tb(env);
12559fddaa0cSbellard }
12569fddaa0cSbellard 
125705390248SAndreas Färber uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
12589fddaa0cSbellard {
12599fddaa0cSbellard     return cpu_ppc_get_tb(env) >> 32;
12609fddaa0cSbellard }
12619fddaa0cSbellard 
126205390248SAndreas Färber uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
12639fddaa0cSbellard {
1264b711de95SAurelien Jarno     return cpu_ppc_get_tb(env);
12659fddaa0cSbellard }
12669fddaa0cSbellard 
126705390248SAndreas Färber uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
12689fddaa0cSbellard {
1269a062e36cSj_mayer     return cpu_ppc_get_tb(env) >> 32;
12709fddaa0cSbellard }
12719fddaa0cSbellard 
127205390248SAndreas Färber uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
127376a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_load_tbu") ));
127476a66253Sj_mayer 
127505390248SAndreas Färber uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
12769fddaa0cSbellard {
127776a66253Sj_mayer     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
12789fddaa0cSbellard }
12799fddaa0cSbellard 
1280a750fc0bSj_mayer /* XXX: to be fixed */
128173b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
1282a750fc0bSj_mayer {
1283a750fc0bSj_mayer     return -1;
1284a750fc0bSj_mayer }
1285a750fc0bSj_mayer 
128673b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
1287a750fc0bSj_mayer {
1288a750fc0bSj_mayer     return -1;
1289a750fc0bSj_mayer }
1290a750fc0bSj_mayer 
1291001faf32SBlue Swirl #define EXCP_DUMP(env, fmt, ...)                                        \
1292e1833e1fSj_mayer do {                                                                    \
1293001faf32SBlue Swirl     fprintf(stderr, fmt , ## __VA_ARGS__);                              \
1294e1833e1fSj_mayer     cpu_dump_state(env, stderr, fprintf, 0);                            \
1295001faf32SBlue Swirl     qemu_log(fmt, ## __VA_ARGS__);                                      \
1296eeacee4dSBlue Swirl     if (qemu_log_enabled()) {                                           \
129793fcfe39Saliguori         log_cpu_state(env, 0);                                          \
1298eeacee4dSBlue Swirl     }                                                                   \
1299e1833e1fSj_mayer } while (0)
1300e1833e1fSj_mayer 
130156f066bbSNathan Froyd static int do_store_exclusive(CPUPPCState *env)
130256f066bbSNathan Froyd {
130356f066bbSNathan Froyd     target_ulong addr;
130456f066bbSNathan Froyd     target_ulong page_addr;
130556f066bbSNathan Froyd     target_ulong val;
130656f066bbSNathan Froyd     int flags;
130756f066bbSNathan Froyd     int segv = 0;
130856f066bbSNathan Froyd 
130956f066bbSNathan Froyd     addr = env->reserve_ea;
131056f066bbSNathan Froyd     page_addr = addr & TARGET_PAGE_MASK;
131156f066bbSNathan Froyd     start_exclusive();
131256f066bbSNathan Froyd     mmap_lock();
131356f066bbSNathan Froyd     flags = page_get_flags(page_addr);
131456f066bbSNathan Froyd     if ((flags & PAGE_READ) == 0) {
131556f066bbSNathan Froyd         segv = 1;
131656f066bbSNathan Froyd     } else {
131756f066bbSNathan Froyd         int reg = env->reserve_info & 0x1f;
131856f066bbSNathan Froyd         int size = (env->reserve_info >> 5) & 0xf;
131956f066bbSNathan Froyd         int stored = 0;
132056f066bbSNathan Froyd 
132156f066bbSNathan Froyd         if (addr == env->reserve_addr) {
132256f066bbSNathan Froyd             switch (size) {
132356f066bbSNathan Froyd             case 1: segv = get_user_u8(val, addr); break;
132456f066bbSNathan Froyd             case 2: segv = get_user_u16(val, addr); break;
132556f066bbSNathan Froyd             case 4: segv = get_user_u32(val, addr); break;
132656f066bbSNathan Froyd #if defined(TARGET_PPC64)
132756f066bbSNathan Froyd             case 8: segv = get_user_u64(val, addr); break;
132856f066bbSNathan Froyd #endif
132956f066bbSNathan Froyd             default: abort();
133056f066bbSNathan Froyd             }
133156f066bbSNathan Froyd             if (!segv && val == env->reserve_val) {
133256f066bbSNathan Froyd                 val = env->gpr[reg];
133356f066bbSNathan Froyd                 switch (size) {
133456f066bbSNathan Froyd                 case 1: segv = put_user_u8(val, addr); break;
133556f066bbSNathan Froyd                 case 2: segv = put_user_u16(val, addr); break;
133656f066bbSNathan Froyd                 case 4: segv = put_user_u32(val, addr); break;
133756f066bbSNathan Froyd #if defined(TARGET_PPC64)
133856f066bbSNathan Froyd                 case 8: segv = put_user_u64(val, addr); break;
133956f066bbSNathan Froyd #endif
134056f066bbSNathan Froyd                 default: abort();
134156f066bbSNathan Froyd                 }
134256f066bbSNathan Froyd                 if (!segv) {
134356f066bbSNathan Froyd                     stored = 1;
134456f066bbSNathan Froyd                 }
134556f066bbSNathan Froyd             }
134656f066bbSNathan Froyd         }
134756f066bbSNathan Froyd         env->crf[0] = (stored << 1) | xer_so;
134856f066bbSNathan Froyd         env->reserve_addr = (target_ulong)-1;
134956f066bbSNathan Froyd     }
135056f066bbSNathan Froyd     if (!segv) {
135156f066bbSNathan Froyd         env->nip += 4;
135256f066bbSNathan Froyd     }
135356f066bbSNathan Froyd     mmap_unlock();
135456f066bbSNathan Froyd     end_exclusive();
135556f066bbSNathan Froyd     return segv;
135656f066bbSNathan Froyd }
135756f066bbSNathan Froyd 
135867867308Sbellard void cpu_loop(CPUPPCState *env)
135967867308Sbellard {
1360c227f099SAnthony Liguori     target_siginfo_t info;
136161190b14Sbellard     int trapnr;
13629e0e2f96SRichard Henderson     target_ulong ret;
136367867308Sbellard 
136467867308Sbellard     for(;;) {
136556f066bbSNathan Froyd         cpu_exec_start(env);
136667867308Sbellard         trapnr = cpu_ppc_exec(env);
136756f066bbSNathan Froyd         cpu_exec_end(env);
136867867308Sbellard         switch(trapnr) {
1369e1833e1fSj_mayer         case POWERPC_EXCP_NONE:
1370e1833e1fSj_mayer             /* Just go on */
137167867308Sbellard             break;
1372e1833e1fSj_mayer         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
1373e1833e1fSj_mayer             cpu_abort(env, "Critical interrupt while in user mode. "
1374e1833e1fSj_mayer                       "Aborting\n");
1375e1833e1fSj_mayer             break;
1376e1833e1fSj_mayer         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
1377e1833e1fSj_mayer             cpu_abort(env, "Machine check exception while in user mode. "
1378e1833e1fSj_mayer                       "Aborting\n");
1379e1833e1fSj_mayer             break;
1380e1833e1fSj_mayer         case POWERPC_EXCP_DSI:      /* Data storage exception                */
138190e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
1382e1833e1fSj_mayer                       env->spr[SPR_DAR]);
1383e1833e1fSj_mayer             /* XXX: check this. Seems bugged */
1384e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1385e1833e1fSj_mayer             case 0x40000000:
1386e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1387e1833e1fSj_mayer                 info.si_errno = 0;
1388e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1389e1833e1fSj_mayer                 break;
1390e1833e1fSj_mayer             case 0x04000000:
1391e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1392e1833e1fSj_mayer                 info.si_errno = 0;
1393e1833e1fSj_mayer                 info.si_code = TARGET_ILL_ILLADR;
1394e1833e1fSj_mayer                 break;
1395e1833e1fSj_mayer             case 0x08000000:
1396e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1397e1833e1fSj_mayer                 info.si_errno = 0;
1398e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1399e1833e1fSj_mayer                 break;
1400e1833e1fSj_mayer             default:
1401e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1402e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1403e1833e1fSj_mayer                           env->error_code);
1404e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1405e1833e1fSj_mayer                 info.si_errno = 0;
1406e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1407e1833e1fSj_mayer                 break;
1408e1833e1fSj_mayer             }
1409e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip;
1410624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1411e1833e1fSj_mayer             break;
1412e1833e1fSj_mayer         case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
141390e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
141490e189ecSBlue Swirl                       "\n", env->spr[SPR_SRR0]);
1415e1833e1fSj_mayer             /* XXX: check this */
1416e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1417e1833e1fSj_mayer             case 0x40000000:
1418e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1419e1833e1fSj_mayer             info.si_errno = 0;
1420e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1421e1833e1fSj_mayer                 break;
1422e1833e1fSj_mayer             case 0x10000000:
1423e1833e1fSj_mayer             case 0x08000000:
1424e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1425e1833e1fSj_mayer                 info.si_errno = 0;
1426e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1427e1833e1fSj_mayer                 break;
1428e1833e1fSj_mayer             default:
1429e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1430e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1431e1833e1fSj_mayer                           env->error_code);
1432e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1433e1833e1fSj_mayer                 info.si_errno = 0;
1434e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1435e1833e1fSj_mayer                 break;
1436e1833e1fSj_mayer             }
1437e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1438624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1439e1833e1fSj_mayer             break;
1440e1833e1fSj_mayer         case POWERPC_EXCP_EXTERNAL: /* External input                        */
1441e1833e1fSj_mayer             cpu_abort(env, "External interrupt while in user mode. "
1442e1833e1fSj_mayer                       "Aborting\n");
1443e1833e1fSj_mayer             break;
1444e1833e1fSj_mayer         case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
1445e1833e1fSj_mayer             EXCP_DUMP(env, "Unaligned memory access\n");
1446e1833e1fSj_mayer             /* XXX: check this */
1447e1833e1fSj_mayer             info.si_signo = TARGET_SIGBUS;
1448e1833e1fSj_mayer             info.si_errno = 0;
1449e1833e1fSj_mayer             info.si_code = TARGET_BUS_ADRALN;
1450e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1451624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1452e1833e1fSj_mayer             break;
1453e1833e1fSj_mayer         case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
1454e1833e1fSj_mayer             /* XXX: check this */
1455e1833e1fSj_mayer             switch (env->error_code & ~0xF) {
1456e1833e1fSj_mayer             case POWERPC_EXCP_FP:
1457e1833e1fSj_mayer                 EXCP_DUMP(env, "Floating point program exception\n");
1458e1833e1fSj_mayer                 info.si_signo = TARGET_SIGFPE;
1459e1833e1fSj_mayer                 info.si_errno = 0;
1460e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1461e1833e1fSj_mayer                 case POWERPC_EXCP_FP_OX:
1462e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTOVF;
1463e1833e1fSj_mayer                     break;
1464e1833e1fSj_mayer                 case POWERPC_EXCP_FP_UX:
1465e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTUND;
1466e1833e1fSj_mayer                     break;
1467e1833e1fSj_mayer                 case POWERPC_EXCP_FP_ZX:
1468e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXZDZ:
1469e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTDIV;
1470e1833e1fSj_mayer                     break;
1471e1833e1fSj_mayer                 case POWERPC_EXCP_FP_XX:
1472e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTRES;
1473e1833e1fSj_mayer                     break;
1474e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSOFT:
1475e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTINV;
1476e1833e1fSj_mayer                     break;
14777c58044cSj_mayer                 case POWERPC_EXCP_FP_VXSNAN:
1478e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXISI:
1479e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIDI:
1480e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIMZ:
1481e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXVC:
1482e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSQRT:
1483e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXCVI:
1484e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTSUB;
1485e1833e1fSj_mayer                     break;
1486e1833e1fSj_mayer                 default:
1487e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
1488e1833e1fSj_mayer                               env->error_code);
1489e1833e1fSj_mayer                     break;
1490e1833e1fSj_mayer                 }
1491e1833e1fSj_mayer                 break;
1492e1833e1fSj_mayer             case POWERPC_EXCP_INVAL:
1493e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid instruction\n");
1494e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1495e1833e1fSj_mayer                 info.si_errno = 0;
1496e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1497e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_INVAL:
1498e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPC;
1499e1833e1fSj_mayer                     break;
1500e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_LSWX:
1501e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPN;
1502e1833e1fSj_mayer                     break;
1503e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_SPR:
1504e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1505e1833e1fSj_mayer                     break;
1506e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_FP:
1507e1833e1fSj_mayer                     info.si_code = TARGET_ILL_COPROC;
1508e1833e1fSj_mayer                     break;
1509e1833e1fSj_mayer                 default:
1510e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
1511e1833e1fSj_mayer                               env->error_code & 0xF);
1512e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLADR;
1513e1833e1fSj_mayer                     break;
1514e1833e1fSj_mayer                 }
1515e1833e1fSj_mayer                 break;
1516e1833e1fSj_mayer             case POWERPC_EXCP_PRIV:
1517e1833e1fSj_mayer                 EXCP_DUMP(env, "Privilege violation\n");
1518e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1519e1833e1fSj_mayer                 info.si_errno = 0;
1520e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1521e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_OPC:
1522e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1523e1833e1fSj_mayer                     break;
1524e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_REG:
1525e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1526e1833e1fSj_mayer                     break;
1527e1833e1fSj_mayer                 default:
1528e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
1529e1833e1fSj_mayer                               env->error_code & 0xF);
1530e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1531e1833e1fSj_mayer                     break;
1532e1833e1fSj_mayer                 }
1533e1833e1fSj_mayer                 break;
1534e1833e1fSj_mayer             case POWERPC_EXCP_TRAP:
1535e1833e1fSj_mayer                 cpu_abort(env, "Tried to call a TRAP\n");
1536e1833e1fSj_mayer                 break;
1537e1833e1fSj_mayer             default:
1538e1833e1fSj_mayer                 /* Should not happen ! */
1539e1833e1fSj_mayer                 cpu_abort(env, "Unknown program exception (%02x)\n",
1540e1833e1fSj_mayer                           env->error_code);
1541e1833e1fSj_mayer                 break;
1542e1833e1fSj_mayer             }
1543e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1544624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1545e1833e1fSj_mayer             break;
1546e1833e1fSj_mayer         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
1547e1833e1fSj_mayer             EXCP_DUMP(env, "No floating point allowed\n");
1548e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1549e1833e1fSj_mayer             info.si_errno = 0;
1550e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1551e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1552624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1553e1833e1fSj_mayer             break;
1554e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
1555e1833e1fSj_mayer             cpu_abort(env, "Syscall exception while in user mode. "
1556e1833e1fSj_mayer                       "Aborting\n");
1557e1833e1fSj_mayer             break;
1558e1833e1fSj_mayer         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
1559e1833e1fSj_mayer             EXCP_DUMP(env, "No APU instruction allowed\n");
1560e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1561e1833e1fSj_mayer             info.si_errno = 0;
1562e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1563e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1564624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1565e1833e1fSj_mayer             break;
1566e1833e1fSj_mayer         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
1567e1833e1fSj_mayer             cpu_abort(env, "Decrementer interrupt while in user mode. "
1568e1833e1fSj_mayer                       "Aborting\n");
1569e1833e1fSj_mayer             break;
1570e1833e1fSj_mayer         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
1571e1833e1fSj_mayer             cpu_abort(env, "Fix interval timer interrupt while in user mode. "
1572e1833e1fSj_mayer                       "Aborting\n");
1573e1833e1fSj_mayer             break;
1574e1833e1fSj_mayer         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
1575e1833e1fSj_mayer             cpu_abort(env, "Watchdog timer interrupt while in user mode. "
1576e1833e1fSj_mayer                       "Aborting\n");
1577e1833e1fSj_mayer             break;
1578e1833e1fSj_mayer         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
1579e1833e1fSj_mayer             cpu_abort(env, "Data TLB exception while in user mode. "
1580e1833e1fSj_mayer                       "Aborting\n");
1581e1833e1fSj_mayer             break;
1582e1833e1fSj_mayer         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
1583e1833e1fSj_mayer             cpu_abort(env, "Instruction TLB exception while in user mode. "
1584e1833e1fSj_mayer                       "Aborting\n");
1585e1833e1fSj_mayer             break;
1586e1833e1fSj_mayer         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
1587e1833e1fSj_mayer             EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
1588e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1589e1833e1fSj_mayer             info.si_errno = 0;
1590e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1591e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1592624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1593e1833e1fSj_mayer             break;
1594e1833e1fSj_mayer         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
1595e1833e1fSj_mayer             cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
1596e1833e1fSj_mayer             break;
1597e1833e1fSj_mayer         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
1598e1833e1fSj_mayer             cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
1599e1833e1fSj_mayer             break;
1600e1833e1fSj_mayer         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
1601e1833e1fSj_mayer             cpu_abort(env, "Performance monitor exception not handled\n");
1602e1833e1fSj_mayer             break;
1603e1833e1fSj_mayer         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
1604e1833e1fSj_mayer             cpu_abort(env, "Doorbell interrupt while in user mode. "
1605e1833e1fSj_mayer                        "Aborting\n");
1606e1833e1fSj_mayer             break;
1607e1833e1fSj_mayer         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
1608e1833e1fSj_mayer             cpu_abort(env, "Doorbell critical interrupt while in user mode. "
1609e1833e1fSj_mayer                       "Aborting\n");
1610e1833e1fSj_mayer             break;
1611e1833e1fSj_mayer         case POWERPC_EXCP_RESET:    /* System reset exception                */
1612e1833e1fSj_mayer             cpu_abort(env, "Reset interrupt while in user mode. "
1613e1833e1fSj_mayer                       "Aborting\n");
1614e1833e1fSj_mayer             break;
1615e1833e1fSj_mayer         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
1616e1833e1fSj_mayer             cpu_abort(env, "Data segment exception while in user mode. "
1617e1833e1fSj_mayer                       "Aborting\n");
1618e1833e1fSj_mayer             break;
1619e1833e1fSj_mayer         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
1620e1833e1fSj_mayer             cpu_abort(env, "Instruction segment exception "
1621e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1622e1833e1fSj_mayer             break;
1623e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1624e1833e1fSj_mayer         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
1625e1833e1fSj_mayer             cpu_abort(env, "Hypervisor decrementer interrupt "
1626e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1627e1833e1fSj_mayer             break;
1628e1833e1fSj_mayer         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
1629e1833e1fSj_mayer             /* Nothing to do:
1630e1833e1fSj_mayer              * we use this exception to emulate step-by-step execution mode.
1631e1833e1fSj_mayer              */
1632e1833e1fSj_mayer             break;
1633e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1634e1833e1fSj_mayer         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
1635e1833e1fSj_mayer             cpu_abort(env, "Hypervisor data storage exception "
1636e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1637e1833e1fSj_mayer             break;
1638e1833e1fSj_mayer         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
1639e1833e1fSj_mayer             cpu_abort(env, "Hypervisor instruction storage exception "
1640e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1641e1833e1fSj_mayer             break;
1642e1833e1fSj_mayer         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
1643e1833e1fSj_mayer             cpu_abort(env, "Hypervisor data segment exception "
1644e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1645e1833e1fSj_mayer             break;
1646e1833e1fSj_mayer         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
1647e1833e1fSj_mayer             cpu_abort(env, "Hypervisor instruction segment exception "
1648e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1649e1833e1fSj_mayer             break;
1650e1833e1fSj_mayer         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
1651e1833e1fSj_mayer             EXCP_DUMP(env, "No Altivec instructions allowed\n");
1652e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1653e1833e1fSj_mayer             info.si_errno = 0;
1654e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1655e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1656624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1657e1833e1fSj_mayer             break;
1658e1833e1fSj_mayer         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
1659b4916d7bSDong Xu Wang             cpu_abort(env, "Programmable interval timer interrupt "
1660e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1661e1833e1fSj_mayer             break;
1662e1833e1fSj_mayer         case POWERPC_EXCP_IO:       /* IO error exception                    */
1663e1833e1fSj_mayer             cpu_abort(env, "IO error exception while in user mode. "
1664e1833e1fSj_mayer                       "Aborting\n");
1665e1833e1fSj_mayer             break;
1666e1833e1fSj_mayer         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
1667e1833e1fSj_mayer             cpu_abort(env, "Run mode exception while in user mode. "
1668e1833e1fSj_mayer                       "Aborting\n");
1669e1833e1fSj_mayer             break;
1670e1833e1fSj_mayer         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
1671e1833e1fSj_mayer             cpu_abort(env, "Emulation trap exception not handled\n");
1672e1833e1fSj_mayer             break;
1673e1833e1fSj_mayer         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
1674e1833e1fSj_mayer             cpu_abort(env, "Instruction fetch TLB exception "
1675e1833e1fSj_mayer                       "while in user-mode. Aborting");
1676e1833e1fSj_mayer             break;
1677e1833e1fSj_mayer         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
1678e1833e1fSj_mayer             cpu_abort(env, "Data load TLB exception while in user-mode. "
1679e1833e1fSj_mayer                       "Aborting");
1680e1833e1fSj_mayer             break;
1681e1833e1fSj_mayer         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
1682e1833e1fSj_mayer             cpu_abort(env, "Data store TLB exception while in user-mode. "
1683e1833e1fSj_mayer                       "Aborting");
1684e1833e1fSj_mayer             break;
1685e1833e1fSj_mayer         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
1686e1833e1fSj_mayer             cpu_abort(env, "Floating-point assist exception not handled\n");
1687e1833e1fSj_mayer             break;
1688e1833e1fSj_mayer         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
1689e1833e1fSj_mayer             cpu_abort(env, "Instruction address breakpoint exception "
1690e1833e1fSj_mayer                       "not handled\n");
1691e1833e1fSj_mayer             break;
1692e1833e1fSj_mayer         case POWERPC_EXCP_SMI:      /* System management interrupt           */
1693e1833e1fSj_mayer             cpu_abort(env, "System management interrupt while in user mode. "
1694e1833e1fSj_mayer                       "Aborting\n");
1695e1833e1fSj_mayer             break;
1696e1833e1fSj_mayer         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
1697e1833e1fSj_mayer             cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
1698e1833e1fSj_mayer                       "Aborting\n");
1699e1833e1fSj_mayer             break;
1700e1833e1fSj_mayer         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
1701e1833e1fSj_mayer             cpu_abort(env, "Performance monitor exception not handled\n");
1702e1833e1fSj_mayer             break;
1703e1833e1fSj_mayer         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
1704e1833e1fSj_mayer             cpu_abort(env, "Vector assist exception not handled\n");
1705e1833e1fSj_mayer             break;
1706e1833e1fSj_mayer         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
1707e1833e1fSj_mayer             cpu_abort(env, "Soft patch exception not handled\n");
1708e1833e1fSj_mayer             break;
1709e1833e1fSj_mayer         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
1710e1833e1fSj_mayer             cpu_abort(env, "Maintenance exception while in user mode. "
1711e1833e1fSj_mayer                       "Aborting\n");
1712e1833e1fSj_mayer             break;
1713e1833e1fSj_mayer         case POWERPC_EXCP_STOP:     /* stop translation                      */
1714e1833e1fSj_mayer             /* We did invalidate the instruction cache. Go on */
1715e1833e1fSj_mayer             break;
1716e1833e1fSj_mayer         case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
1717e1833e1fSj_mayer             /* We just stopped because of a branch. Go on */
1718e1833e1fSj_mayer             break;
1719e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL_USER:
1720e1833e1fSj_mayer             /* system call in user-mode emulation */
172167867308Sbellard             /* WARNING:
172267867308Sbellard              * PPC ABI uses overflow flag in cr0 to signal an error
172367867308Sbellard              * in syscalls.
172467867308Sbellard              */
172567867308Sbellard             env->crf[0] &= ~0x1;
172667867308Sbellard             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
172767867308Sbellard                              env->gpr[5], env->gpr[6], env->gpr[7],
17285945cfcbSPeter Maydell                              env->gpr[8], 0, 0);
17299e0e2f96SRichard Henderson             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
1730bcd4933aSNathan Froyd                 /* Returning from a successful sigreturn syscall.
1731bcd4933aSNathan Froyd                    Avoid corrupting register state.  */
1732bcd4933aSNathan Froyd                 break;
1733bcd4933aSNathan Froyd             }
17349e0e2f96SRichard Henderson             if (ret > (target_ulong)(-515)) {
173567867308Sbellard                 env->crf[0] |= 0x1;
173667867308Sbellard                 ret = -ret;
173767867308Sbellard             }
173867867308Sbellard             env->gpr[3] = ret;
173961190b14Sbellard             break;
174056f066bbSNathan Froyd         case POWERPC_EXCP_STCX:
174156f066bbSNathan Froyd             if (do_store_exclusive(env)) {
174256f066bbSNathan Froyd                 info.si_signo = TARGET_SIGSEGV;
174356f066bbSNathan Froyd                 info.si_errno = 0;
174456f066bbSNathan Froyd                 info.si_code = TARGET_SEGV_MAPERR;
174556f066bbSNathan Froyd                 info._sifields._sigfault._addr = env->nip;
174656f066bbSNathan Froyd                 queue_signal(env, info.si_signo, &info);
174756f066bbSNathan Froyd             }
174856f066bbSNathan Froyd             break;
174971f75756Saurel32         case EXCP_DEBUG:
175071f75756Saurel32             {
175171f75756Saurel32                 int sig;
175271f75756Saurel32 
175371f75756Saurel32                 sig = gdb_handlesig(env, TARGET_SIGTRAP);
175471f75756Saurel32                 if (sig) {
175571f75756Saurel32                     info.si_signo = sig;
175671f75756Saurel32                     info.si_errno = 0;
175771f75756Saurel32                     info.si_code = TARGET_TRAP_BRKPT;
175871f75756Saurel32                     queue_signal(env, info.si_signo, &info);
175971f75756Saurel32                   }
176071f75756Saurel32             }
176171f75756Saurel32             break;
176256ba31ffSj_mayer         case EXCP_INTERRUPT:
176356ba31ffSj_mayer             /* just indicate that signals should be handled asap */
176456ba31ffSj_mayer             break;
176561190b14Sbellard         default:
1766e1833e1fSj_mayer             cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
176767867308Sbellard             break;
176867867308Sbellard         }
176967867308Sbellard         process_pending_signals(env);
177067867308Sbellard     }
177167867308Sbellard }
177267867308Sbellard #endif
177367867308Sbellard 
1774048f6b4dSbellard #ifdef TARGET_MIPS
1775048f6b4dSbellard 
1776048f6b4dSbellard #define MIPS_SYS(name, args) args,
1777048f6b4dSbellard 
1778048f6b4dSbellard static const uint8_t mips_syscall_args[] = {
177929fb0f25SAn-Cheng Huang 	MIPS_SYS(sys_syscall	, 8)	/* 4000 */
1780048f6b4dSbellard 	MIPS_SYS(sys_exit	, 1)
1781048f6b4dSbellard 	MIPS_SYS(sys_fork	, 0)
1782048f6b4dSbellard 	MIPS_SYS(sys_read	, 3)
1783048f6b4dSbellard 	MIPS_SYS(sys_write	, 3)
1784048f6b4dSbellard 	MIPS_SYS(sys_open	, 3)	/* 4005 */
1785048f6b4dSbellard 	MIPS_SYS(sys_close	, 1)
1786048f6b4dSbellard 	MIPS_SYS(sys_waitpid	, 3)
1787048f6b4dSbellard 	MIPS_SYS(sys_creat	, 2)
1788048f6b4dSbellard 	MIPS_SYS(sys_link	, 2)
1789048f6b4dSbellard 	MIPS_SYS(sys_unlink	, 1)	/* 4010 */
1790048f6b4dSbellard 	MIPS_SYS(sys_execve	, 0)
1791048f6b4dSbellard 	MIPS_SYS(sys_chdir	, 1)
1792048f6b4dSbellard 	MIPS_SYS(sys_time	, 1)
1793048f6b4dSbellard 	MIPS_SYS(sys_mknod	, 3)
1794048f6b4dSbellard 	MIPS_SYS(sys_chmod	, 2)	/* 4015 */
1795048f6b4dSbellard 	MIPS_SYS(sys_lchown	, 3)
1796048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1797048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_stat */
1798048f6b4dSbellard 	MIPS_SYS(sys_lseek	, 3)
1799048f6b4dSbellard 	MIPS_SYS(sys_getpid	, 0)	/* 4020 */
1800048f6b4dSbellard 	MIPS_SYS(sys_mount	, 5)
1801048f6b4dSbellard 	MIPS_SYS(sys_oldumount	, 1)
1802048f6b4dSbellard 	MIPS_SYS(sys_setuid	, 1)
1803048f6b4dSbellard 	MIPS_SYS(sys_getuid	, 0)
1804048f6b4dSbellard 	MIPS_SYS(sys_stime	, 1)	/* 4025 */
1805048f6b4dSbellard 	MIPS_SYS(sys_ptrace	, 4)
1806048f6b4dSbellard 	MIPS_SYS(sys_alarm	, 1)
1807048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_fstat */
1808048f6b4dSbellard 	MIPS_SYS(sys_pause	, 0)
1809048f6b4dSbellard 	MIPS_SYS(sys_utime	, 2)	/* 4030 */
1810048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1811048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1812048f6b4dSbellard 	MIPS_SYS(sys_access	, 2)
1813048f6b4dSbellard 	MIPS_SYS(sys_nice	, 1)
1814048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4035 */
1815048f6b4dSbellard 	MIPS_SYS(sys_sync	, 0)
1816048f6b4dSbellard 	MIPS_SYS(sys_kill	, 2)
1817048f6b4dSbellard 	MIPS_SYS(sys_rename	, 2)
1818048f6b4dSbellard 	MIPS_SYS(sys_mkdir	, 2)
1819048f6b4dSbellard 	MIPS_SYS(sys_rmdir	, 1)	/* 4040 */
1820048f6b4dSbellard 	MIPS_SYS(sys_dup		, 1)
1821048f6b4dSbellard 	MIPS_SYS(sys_pipe	, 0)
1822048f6b4dSbellard 	MIPS_SYS(sys_times	, 1)
1823048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1824048f6b4dSbellard 	MIPS_SYS(sys_brk		, 1)	/* 4045 */
1825048f6b4dSbellard 	MIPS_SYS(sys_setgid	, 1)
1826048f6b4dSbellard 	MIPS_SYS(sys_getgid	, 0)
1827048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was signal(2) */
1828048f6b4dSbellard 	MIPS_SYS(sys_geteuid	, 0)
1829048f6b4dSbellard 	MIPS_SYS(sys_getegid	, 0)	/* 4050 */
1830048f6b4dSbellard 	MIPS_SYS(sys_acct	, 0)
1831048f6b4dSbellard 	MIPS_SYS(sys_umount	, 2)
1832048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1833048f6b4dSbellard 	MIPS_SYS(sys_ioctl	, 3)
1834048f6b4dSbellard 	MIPS_SYS(sys_fcntl	, 3)	/* 4055 */
1835048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 2)
1836048f6b4dSbellard 	MIPS_SYS(sys_setpgid	, 2)
1837048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1838048f6b4dSbellard 	MIPS_SYS(sys_olduname	, 1)
1839048f6b4dSbellard 	MIPS_SYS(sys_umask	, 1)	/* 4060 */
1840048f6b4dSbellard 	MIPS_SYS(sys_chroot	, 1)
1841048f6b4dSbellard 	MIPS_SYS(sys_ustat	, 2)
1842048f6b4dSbellard 	MIPS_SYS(sys_dup2	, 2)
1843048f6b4dSbellard 	MIPS_SYS(sys_getppid	, 0)
1844048f6b4dSbellard 	MIPS_SYS(sys_getpgrp	, 0)	/* 4065 */
1845048f6b4dSbellard 	MIPS_SYS(sys_setsid	, 0)
1846048f6b4dSbellard 	MIPS_SYS(sys_sigaction	, 3)
1847048f6b4dSbellard 	MIPS_SYS(sys_sgetmask	, 0)
1848048f6b4dSbellard 	MIPS_SYS(sys_ssetmask	, 1)
1849048f6b4dSbellard 	MIPS_SYS(sys_setreuid	, 2)	/* 4070 */
1850048f6b4dSbellard 	MIPS_SYS(sys_setregid	, 2)
1851048f6b4dSbellard 	MIPS_SYS(sys_sigsuspend	, 0)
1852048f6b4dSbellard 	MIPS_SYS(sys_sigpending	, 1)
1853048f6b4dSbellard 	MIPS_SYS(sys_sethostname	, 2)
1854048f6b4dSbellard 	MIPS_SYS(sys_setrlimit	, 2)	/* 4075 */
1855048f6b4dSbellard 	MIPS_SYS(sys_getrlimit	, 2)
1856048f6b4dSbellard 	MIPS_SYS(sys_getrusage	, 2)
1857048f6b4dSbellard 	MIPS_SYS(sys_gettimeofday, 2)
1858048f6b4dSbellard 	MIPS_SYS(sys_settimeofday, 2)
1859048f6b4dSbellard 	MIPS_SYS(sys_getgroups	, 2)	/* 4080 */
1860048f6b4dSbellard 	MIPS_SYS(sys_setgroups	, 2)
1861048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* old_select */
1862048f6b4dSbellard 	MIPS_SYS(sys_symlink	, 2)
1863048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_lstat */
1864048f6b4dSbellard 	MIPS_SYS(sys_readlink	, 3)	/* 4085 */
1865048f6b4dSbellard 	MIPS_SYS(sys_uselib	, 1)
1866048f6b4dSbellard 	MIPS_SYS(sys_swapon	, 2)
1867048f6b4dSbellard 	MIPS_SYS(sys_reboot	, 3)
1868048f6b4dSbellard 	MIPS_SYS(old_readdir	, 3)
1869048f6b4dSbellard 	MIPS_SYS(old_mmap	, 6)	/* 4090 */
1870048f6b4dSbellard 	MIPS_SYS(sys_munmap	, 2)
1871048f6b4dSbellard 	MIPS_SYS(sys_truncate	, 2)
1872048f6b4dSbellard 	MIPS_SYS(sys_ftruncate	, 2)
1873048f6b4dSbellard 	MIPS_SYS(sys_fchmod	, 2)
1874048f6b4dSbellard 	MIPS_SYS(sys_fchown	, 3)	/* 4095 */
1875048f6b4dSbellard 	MIPS_SYS(sys_getpriority	, 2)
1876048f6b4dSbellard 	MIPS_SYS(sys_setpriority	, 3)
1877048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1878048f6b4dSbellard 	MIPS_SYS(sys_statfs	, 2)
1879048f6b4dSbellard 	MIPS_SYS(sys_fstatfs	, 2)	/* 4100 */
1880048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was ioperm(2) */
1881048f6b4dSbellard 	MIPS_SYS(sys_socketcall	, 2)
1882048f6b4dSbellard 	MIPS_SYS(sys_syslog	, 3)
1883048f6b4dSbellard 	MIPS_SYS(sys_setitimer	, 3)
1884048f6b4dSbellard 	MIPS_SYS(sys_getitimer	, 2)	/* 4105 */
1885048f6b4dSbellard 	MIPS_SYS(sys_newstat	, 2)
1886048f6b4dSbellard 	MIPS_SYS(sys_newlstat	, 2)
1887048f6b4dSbellard 	MIPS_SYS(sys_newfstat	, 2)
1888048f6b4dSbellard 	MIPS_SYS(sys_uname	, 1)
1889048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4110 was iopl(2) */
1890048f6b4dSbellard 	MIPS_SYS(sys_vhangup	, 0)
1891048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_idle() */
1892048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_vm86 */
1893048f6b4dSbellard 	MIPS_SYS(sys_wait4	, 4)
1894048f6b4dSbellard 	MIPS_SYS(sys_swapoff	, 1)	/* 4115 */
1895048f6b4dSbellard 	MIPS_SYS(sys_sysinfo	, 1)
1896048f6b4dSbellard 	MIPS_SYS(sys_ipc		, 6)
1897048f6b4dSbellard 	MIPS_SYS(sys_fsync	, 1)
1898048f6b4dSbellard 	MIPS_SYS(sys_sigreturn	, 0)
189918113962SPaul Brook 	MIPS_SYS(sys_clone	, 6)	/* 4120 */
1900048f6b4dSbellard 	MIPS_SYS(sys_setdomainname, 2)
1901048f6b4dSbellard 	MIPS_SYS(sys_newuname	, 1)
1902048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_modify_ldt */
1903048f6b4dSbellard 	MIPS_SYS(sys_adjtimex	, 1)
1904048f6b4dSbellard 	MIPS_SYS(sys_mprotect	, 3)	/* 4125 */
1905048f6b4dSbellard 	MIPS_SYS(sys_sigprocmask	, 3)
1906048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was create_module */
1907048f6b4dSbellard 	MIPS_SYS(sys_init_module	, 5)
1908048f6b4dSbellard 	MIPS_SYS(sys_delete_module, 1)
1909048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4130	was get_kernel_syms */
1910048f6b4dSbellard 	MIPS_SYS(sys_quotactl	, 0)
1911048f6b4dSbellard 	MIPS_SYS(sys_getpgid	, 1)
1912048f6b4dSbellard 	MIPS_SYS(sys_fchdir	, 1)
1913048f6b4dSbellard 	MIPS_SYS(sys_bdflush	, 2)
1914048f6b4dSbellard 	MIPS_SYS(sys_sysfs	, 3)	/* 4135 */
1915048f6b4dSbellard 	MIPS_SYS(sys_personality	, 1)
1916048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* for afs_syscall */
1917048f6b4dSbellard 	MIPS_SYS(sys_setfsuid	, 1)
1918048f6b4dSbellard 	MIPS_SYS(sys_setfsgid	, 1)
1919048f6b4dSbellard 	MIPS_SYS(sys_llseek	, 5)	/* 4140 */
1920048f6b4dSbellard 	MIPS_SYS(sys_getdents	, 3)
1921048f6b4dSbellard 	MIPS_SYS(sys_select	, 5)
1922048f6b4dSbellard 	MIPS_SYS(sys_flock	, 2)
1923048f6b4dSbellard 	MIPS_SYS(sys_msync	, 3)
1924048f6b4dSbellard 	MIPS_SYS(sys_readv	, 3)	/* 4145 */
1925048f6b4dSbellard 	MIPS_SYS(sys_writev	, 3)
1926048f6b4dSbellard 	MIPS_SYS(sys_cacheflush	, 3)
1927048f6b4dSbellard 	MIPS_SYS(sys_cachectl	, 3)
1928048f6b4dSbellard 	MIPS_SYS(sys_sysmips	, 4)
1929048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4150 */
1930048f6b4dSbellard 	MIPS_SYS(sys_getsid	, 1)
1931048f6b4dSbellard 	MIPS_SYS(sys_fdatasync	, 0)
1932048f6b4dSbellard 	MIPS_SYS(sys_sysctl	, 1)
1933048f6b4dSbellard 	MIPS_SYS(sys_mlock	, 2)
1934048f6b4dSbellard 	MIPS_SYS(sys_munlock	, 2)	/* 4155 */
1935048f6b4dSbellard 	MIPS_SYS(sys_mlockall	, 1)
1936048f6b4dSbellard 	MIPS_SYS(sys_munlockall	, 0)
1937048f6b4dSbellard 	MIPS_SYS(sys_sched_setparam, 2)
1938048f6b4dSbellard 	MIPS_SYS(sys_sched_getparam, 2)
1939048f6b4dSbellard 	MIPS_SYS(sys_sched_setscheduler, 3)	/* 4160 */
1940048f6b4dSbellard 	MIPS_SYS(sys_sched_getscheduler, 1)
1941048f6b4dSbellard 	MIPS_SYS(sys_sched_yield	, 0)
1942048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_max, 1)
1943048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_min, 1)
1944048f6b4dSbellard 	MIPS_SYS(sys_sched_rr_get_interval, 2)	/* 4165 */
1945048f6b4dSbellard 	MIPS_SYS(sys_nanosleep,	2)
1946048f6b4dSbellard 	MIPS_SYS(sys_mremap	, 4)
1947048f6b4dSbellard 	MIPS_SYS(sys_accept	, 3)
1948048f6b4dSbellard 	MIPS_SYS(sys_bind	, 3)
1949048f6b4dSbellard 	MIPS_SYS(sys_connect	, 3)	/* 4170 */
1950048f6b4dSbellard 	MIPS_SYS(sys_getpeername	, 3)
1951048f6b4dSbellard 	MIPS_SYS(sys_getsockname	, 3)
1952048f6b4dSbellard 	MIPS_SYS(sys_getsockopt	, 5)
1953048f6b4dSbellard 	MIPS_SYS(sys_listen	, 2)
1954048f6b4dSbellard 	MIPS_SYS(sys_recv	, 4)	/* 4175 */
1955048f6b4dSbellard 	MIPS_SYS(sys_recvfrom	, 6)
1956048f6b4dSbellard 	MIPS_SYS(sys_recvmsg	, 3)
1957048f6b4dSbellard 	MIPS_SYS(sys_send	, 4)
1958048f6b4dSbellard 	MIPS_SYS(sys_sendmsg	, 3)
1959048f6b4dSbellard 	MIPS_SYS(sys_sendto	, 6)	/* 4180 */
1960048f6b4dSbellard 	MIPS_SYS(sys_setsockopt	, 5)
1961048f6b4dSbellard 	MIPS_SYS(sys_shutdown	, 2)
1962048f6b4dSbellard 	MIPS_SYS(sys_socket	, 3)
1963048f6b4dSbellard 	MIPS_SYS(sys_socketpair	, 4)
1964048f6b4dSbellard 	MIPS_SYS(sys_setresuid	, 3)	/* 4185 */
1965048f6b4dSbellard 	MIPS_SYS(sys_getresuid	, 3)
1966048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_query_module */
1967048f6b4dSbellard 	MIPS_SYS(sys_poll	, 3)
1968048f6b4dSbellard 	MIPS_SYS(sys_nfsservctl	, 3)
1969048f6b4dSbellard 	MIPS_SYS(sys_setresgid	, 3)	/* 4190 */
1970048f6b4dSbellard 	MIPS_SYS(sys_getresgid	, 3)
1971048f6b4dSbellard 	MIPS_SYS(sys_prctl	, 5)
1972048f6b4dSbellard 	MIPS_SYS(sys_rt_sigreturn, 0)
1973048f6b4dSbellard 	MIPS_SYS(sys_rt_sigaction, 4)
1974048f6b4dSbellard 	MIPS_SYS(sys_rt_sigprocmask, 4)	/* 4195 */
1975048f6b4dSbellard 	MIPS_SYS(sys_rt_sigpending, 2)
1976048f6b4dSbellard 	MIPS_SYS(sys_rt_sigtimedwait, 4)
1977048f6b4dSbellard 	MIPS_SYS(sys_rt_sigqueueinfo, 3)
1978048f6b4dSbellard 	MIPS_SYS(sys_rt_sigsuspend, 0)
1979048f6b4dSbellard 	MIPS_SYS(sys_pread64	, 6)	/* 4200 */
1980048f6b4dSbellard 	MIPS_SYS(sys_pwrite64	, 6)
1981048f6b4dSbellard 	MIPS_SYS(sys_chown	, 3)
1982048f6b4dSbellard 	MIPS_SYS(sys_getcwd	, 2)
1983048f6b4dSbellard 	MIPS_SYS(sys_capget	, 2)
1984048f6b4dSbellard 	MIPS_SYS(sys_capset	, 2)	/* 4205 */
1985053ebb27SWesley W. Terpstra 	MIPS_SYS(sys_sigaltstack	, 2)
1986048f6b4dSbellard 	MIPS_SYS(sys_sendfile	, 4)
1987048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1988048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1989048f6b4dSbellard 	MIPS_SYS(sys_mmap2	, 6)	/* 4210 */
1990048f6b4dSbellard 	MIPS_SYS(sys_truncate64	, 4)
1991048f6b4dSbellard 	MIPS_SYS(sys_ftruncate64	, 4)
1992048f6b4dSbellard 	MIPS_SYS(sys_stat64	, 2)
1993048f6b4dSbellard 	MIPS_SYS(sys_lstat64	, 2)
1994048f6b4dSbellard 	MIPS_SYS(sys_fstat64	, 2)	/* 4215 */
1995048f6b4dSbellard 	MIPS_SYS(sys_pivot_root	, 2)
1996048f6b4dSbellard 	MIPS_SYS(sys_mincore	, 3)
1997048f6b4dSbellard 	MIPS_SYS(sys_madvise	, 3)
1998048f6b4dSbellard 	MIPS_SYS(sys_getdents64	, 3)
1999048f6b4dSbellard 	MIPS_SYS(sys_fcntl64	, 3)	/* 4220 */
2000048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2001048f6b4dSbellard 	MIPS_SYS(sys_gettid	, 0)
2002048f6b4dSbellard 	MIPS_SYS(sys_readahead	, 5)
2003048f6b4dSbellard 	MIPS_SYS(sys_setxattr	, 5)
2004048f6b4dSbellard 	MIPS_SYS(sys_lsetxattr	, 5)	/* 4225 */
2005048f6b4dSbellard 	MIPS_SYS(sys_fsetxattr	, 5)
2006048f6b4dSbellard 	MIPS_SYS(sys_getxattr	, 4)
2007048f6b4dSbellard 	MIPS_SYS(sys_lgetxattr	, 4)
2008048f6b4dSbellard 	MIPS_SYS(sys_fgetxattr	, 4)
2009048f6b4dSbellard 	MIPS_SYS(sys_listxattr	, 3)	/* 4230 */
2010048f6b4dSbellard 	MIPS_SYS(sys_llistxattr	, 3)
2011048f6b4dSbellard 	MIPS_SYS(sys_flistxattr	, 3)
2012048f6b4dSbellard 	MIPS_SYS(sys_removexattr	, 2)
2013048f6b4dSbellard 	MIPS_SYS(sys_lremovexattr, 2)
2014048f6b4dSbellard 	MIPS_SYS(sys_fremovexattr, 2)	/* 4235 */
2015048f6b4dSbellard 	MIPS_SYS(sys_tkill	, 2)
2016048f6b4dSbellard 	MIPS_SYS(sys_sendfile64	, 5)
2017048f6b4dSbellard 	MIPS_SYS(sys_futex	, 2)
2018048f6b4dSbellard 	MIPS_SYS(sys_sched_setaffinity, 3)
2019048f6b4dSbellard 	MIPS_SYS(sys_sched_getaffinity, 3)	/* 4240 */
2020048f6b4dSbellard 	MIPS_SYS(sys_io_setup	, 2)
2021048f6b4dSbellard 	MIPS_SYS(sys_io_destroy	, 1)
2022048f6b4dSbellard 	MIPS_SYS(sys_io_getevents, 5)
2023048f6b4dSbellard 	MIPS_SYS(sys_io_submit	, 3)
2024048f6b4dSbellard 	MIPS_SYS(sys_io_cancel	, 3)	/* 4245 */
2025048f6b4dSbellard 	MIPS_SYS(sys_exit_group	, 1)
2026048f6b4dSbellard 	MIPS_SYS(sys_lookup_dcookie, 3)
2027048f6b4dSbellard 	MIPS_SYS(sys_epoll_create, 1)
2028048f6b4dSbellard 	MIPS_SYS(sys_epoll_ctl	, 4)
2029048f6b4dSbellard 	MIPS_SYS(sys_epoll_wait	, 3)	/* 4250 */
2030048f6b4dSbellard 	MIPS_SYS(sys_remap_file_pages, 5)
2031048f6b4dSbellard 	MIPS_SYS(sys_set_tid_address, 1)
2032048f6b4dSbellard 	MIPS_SYS(sys_restart_syscall, 0)
2033048f6b4dSbellard 	MIPS_SYS(sys_fadvise64_64, 7)
2034048f6b4dSbellard 	MIPS_SYS(sys_statfs64	, 3)	/* 4255 */
2035048f6b4dSbellard 	MIPS_SYS(sys_fstatfs64	, 2)
2036048f6b4dSbellard 	MIPS_SYS(sys_timer_create, 3)
2037048f6b4dSbellard 	MIPS_SYS(sys_timer_settime, 4)
2038048f6b4dSbellard 	MIPS_SYS(sys_timer_gettime, 2)
2039048f6b4dSbellard 	MIPS_SYS(sys_timer_getoverrun, 1)	/* 4260 */
2040048f6b4dSbellard 	MIPS_SYS(sys_timer_delete, 1)
2041048f6b4dSbellard 	MIPS_SYS(sys_clock_settime, 2)
2042048f6b4dSbellard 	MIPS_SYS(sys_clock_gettime, 2)
2043048f6b4dSbellard 	MIPS_SYS(sys_clock_getres, 2)
2044048f6b4dSbellard 	MIPS_SYS(sys_clock_nanosleep, 4)	/* 4265 */
2045048f6b4dSbellard 	MIPS_SYS(sys_tgkill	, 3)
2046048f6b4dSbellard 	MIPS_SYS(sys_utimes	, 2)
2047048f6b4dSbellard 	MIPS_SYS(sys_mbind	, 4)
2048048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_get_mempolicy */
2049048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4270 sys_set_mempolicy */
2050048f6b4dSbellard 	MIPS_SYS(sys_mq_open	, 4)
2051048f6b4dSbellard 	MIPS_SYS(sys_mq_unlink	, 1)
2052048f6b4dSbellard 	MIPS_SYS(sys_mq_timedsend, 5)
2053048f6b4dSbellard 	MIPS_SYS(sys_mq_timedreceive, 5)
2054048f6b4dSbellard 	MIPS_SYS(sys_mq_notify	, 2)	/* 4275 */
2055048f6b4dSbellard 	MIPS_SYS(sys_mq_getsetattr, 3)
2056048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_vserver */
2057048f6b4dSbellard 	MIPS_SYS(sys_waitid	, 4)
2058048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
2059048f6b4dSbellard 	MIPS_SYS(sys_add_key	, 5)
2060048f6b4dSbellard 	MIPS_SYS(sys_request_key, 4)
2061048f6b4dSbellard 	MIPS_SYS(sys_keyctl	, 5)
20626f5b89a0Sths 	MIPS_SYS(sys_set_thread_area, 1)
2063388bb21aSths 	MIPS_SYS(sys_inotify_init, 0)
2064388bb21aSths 	MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
2065388bb21aSths 	MIPS_SYS(sys_inotify_rm_watch, 2)
2066388bb21aSths 	MIPS_SYS(sys_migrate_pages, 4)
2067388bb21aSths 	MIPS_SYS(sys_openat, 4)
2068388bb21aSths 	MIPS_SYS(sys_mkdirat, 3)
2069388bb21aSths 	MIPS_SYS(sys_mknodat, 4)	/* 4290 */
2070388bb21aSths 	MIPS_SYS(sys_fchownat, 5)
2071388bb21aSths 	MIPS_SYS(sys_futimesat, 3)
2072388bb21aSths 	MIPS_SYS(sys_fstatat64, 4)
2073388bb21aSths 	MIPS_SYS(sys_unlinkat, 3)
2074388bb21aSths 	MIPS_SYS(sys_renameat, 4)	/* 4295 */
2075388bb21aSths 	MIPS_SYS(sys_linkat, 5)
2076388bb21aSths 	MIPS_SYS(sys_symlinkat, 3)
2077388bb21aSths 	MIPS_SYS(sys_readlinkat, 4)
2078388bb21aSths 	MIPS_SYS(sys_fchmodat, 3)
2079388bb21aSths 	MIPS_SYS(sys_faccessat, 3)	/* 4300 */
2080388bb21aSths 	MIPS_SYS(sys_pselect6, 6)
2081388bb21aSths 	MIPS_SYS(sys_ppoll, 5)
2082388bb21aSths 	MIPS_SYS(sys_unshare, 1)
2083388bb21aSths 	MIPS_SYS(sys_splice, 4)
2084388bb21aSths 	MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
2085388bb21aSths 	MIPS_SYS(sys_tee, 4)
2086388bb21aSths 	MIPS_SYS(sys_vmsplice, 4)
2087388bb21aSths 	MIPS_SYS(sys_move_pages, 6)
2088388bb21aSths 	MIPS_SYS(sys_set_robust_list, 2)
2089388bb21aSths 	MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
2090388bb21aSths 	MIPS_SYS(sys_kexec_load, 4)
2091388bb21aSths 	MIPS_SYS(sys_getcpu, 3)
2092388bb21aSths 	MIPS_SYS(sys_epoll_pwait, 6)
2093388bb21aSths 	MIPS_SYS(sys_ioprio_set, 3)
2094388bb21aSths 	MIPS_SYS(sys_ioprio_get, 2)
2095d979e8ebSPeter Maydell         MIPS_SYS(sys_utimensat, 4)
2096d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd, 3)
2097d979e8ebSPeter Maydell         MIPS_SYS(sys_ni_syscall, 0)     /* was timerfd */
2098d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd, 1)
2099d979e8ebSPeter Maydell         MIPS_SYS(sys_fallocate, 6)      /* 4320 */
2100d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_create, 2)
2101d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_gettime, 2)
2102d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_settime, 4)
2103d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd4, 4)
2104d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd2, 2)       /* 4325 */
2105d979e8ebSPeter Maydell         MIPS_SYS(sys_epoll_create1, 1)
2106d979e8ebSPeter Maydell         MIPS_SYS(sys_dup3, 3)
2107d979e8ebSPeter Maydell         MIPS_SYS(sys_pipe2, 2)
2108d979e8ebSPeter Maydell         MIPS_SYS(sys_inotify_init1, 1)
2109d979e8ebSPeter Maydell         MIPS_SYS(sys_preadv, 6)         /* 4330 */
2110d979e8ebSPeter Maydell         MIPS_SYS(sys_pwritev, 6)
2111d979e8ebSPeter Maydell         MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
2112d979e8ebSPeter Maydell         MIPS_SYS(sys_perf_event_open, 5)
2113d979e8ebSPeter Maydell         MIPS_SYS(sys_accept4, 4)
2114d979e8ebSPeter Maydell         MIPS_SYS(sys_recvmmsg, 5)       /* 4335 */
2115d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_init, 2)
2116d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_mark, 6)
2117d979e8ebSPeter Maydell         MIPS_SYS(sys_prlimit64, 4)
2118d979e8ebSPeter Maydell         MIPS_SYS(sys_name_to_handle_at, 5)
2119d979e8ebSPeter Maydell         MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
2120d979e8ebSPeter Maydell         MIPS_SYS(sys_clock_adjtime, 2)
2121d979e8ebSPeter Maydell         MIPS_SYS(sys_syncfs, 1)
2122048f6b4dSbellard };
2123048f6b4dSbellard 
2124048f6b4dSbellard #undef MIPS_SYS
2125048f6b4dSbellard 
2126590bc601SPaul Brook static int do_store_exclusive(CPUMIPSState *env)
2127590bc601SPaul Brook {
2128590bc601SPaul Brook     target_ulong addr;
2129590bc601SPaul Brook     target_ulong page_addr;
2130590bc601SPaul Brook     target_ulong val;
2131590bc601SPaul Brook     int flags;
2132590bc601SPaul Brook     int segv = 0;
2133590bc601SPaul Brook     int reg;
2134590bc601SPaul Brook     int d;
2135590bc601SPaul Brook 
21365499b6ffSAurelien Jarno     addr = env->lladdr;
2137590bc601SPaul Brook     page_addr = addr & TARGET_PAGE_MASK;
2138590bc601SPaul Brook     start_exclusive();
2139590bc601SPaul Brook     mmap_lock();
2140590bc601SPaul Brook     flags = page_get_flags(page_addr);
2141590bc601SPaul Brook     if ((flags & PAGE_READ) == 0) {
2142590bc601SPaul Brook         segv = 1;
2143590bc601SPaul Brook     } else {
2144590bc601SPaul Brook         reg = env->llreg & 0x1f;
2145590bc601SPaul Brook         d = (env->llreg & 0x20) != 0;
2146590bc601SPaul Brook         if (d) {
2147590bc601SPaul Brook             segv = get_user_s64(val, addr);
2148590bc601SPaul Brook         } else {
2149590bc601SPaul Brook             segv = get_user_s32(val, addr);
2150590bc601SPaul Brook         }
2151590bc601SPaul Brook         if (!segv) {
2152590bc601SPaul Brook             if (val != env->llval) {
2153590bc601SPaul Brook                 env->active_tc.gpr[reg] = 0;
2154590bc601SPaul Brook             } else {
2155590bc601SPaul Brook                 if (d) {
2156590bc601SPaul Brook                     segv = put_user_u64(env->llnewval, addr);
2157590bc601SPaul Brook                 } else {
2158590bc601SPaul Brook                     segv = put_user_u32(env->llnewval, addr);
2159590bc601SPaul Brook                 }
2160590bc601SPaul Brook                 if (!segv) {
2161590bc601SPaul Brook                     env->active_tc.gpr[reg] = 1;
2162590bc601SPaul Brook                 }
2163590bc601SPaul Brook             }
2164590bc601SPaul Brook         }
2165590bc601SPaul Brook     }
21665499b6ffSAurelien Jarno     env->lladdr = -1;
2167590bc601SPaul Brook     if (!segv) {
2168590bc601SPaul Brook         env->active_tc.PC += 4;
2169590bc601SPaul Brook     }
2170590bc601SPaul Brook     mmap_unlock();
2171590bc601SPaul Brook     end_exclusive();
2172590bc601SPaul Brook     return segv;
2173590bc601SPaul Brook }
2174590bc601SPaul Brook 
2175048f6b4dSbellard void cpu_loop(CPUMIPSState *env)
2176048f6b4dSbellard {
2177c227f099SAnthony Liguori     target_siginfo_t info;
2178388bb21aSths     int trapnr, ret;
2179048f6b4dSbellard     unsigned int syscall_num;
2180048f6b4dSbellard 
2181048f6b4dSbellard     for(;;) {
2182590bc601SPaul Brook         cpu_exec_start(env);
2183048f6b4dSbellard         trapnr = cpu_mips_exec(env);
2184590bc601SPaul Brook         cpu_exec_end(env);
2185048f6b4dSbellard         switch(trapnr) {
2186048f6b4dSbellard         case EXCP_SYSCALL:
2187b5dc7732Sths             syscall_num = env->active_tc.gpr[2] - 4000;
2188b5dc7732Sths             env->active_tc.PC += 4;
2189048f6b4dSbellard             if (syscall_num >= sizeof(mips_syscall_args)) {
21907c2f6157SWesley W. Terpstra                 ret = -TARGET_ENOSYS;
2191048f6b4dSbellard             } else {
2192388bb21aSths                 int nb_args;
2193992f48a0Sblueswir1                 abi_ulong sp_reg;
2194992f48a0Sblueswir1                 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
2195388bb21aSths 
2196048f6b4dSbellard                 nb_args = mips_syscall_args[syscall_num];
2197b5dc7732Sths                 sp_reg = env->active_tc.gpr[29];
2198388bb21aSths                 switch (nb_args) {
2199048f6b4dSbellard                 /* these arguments are taken from the stack */
220094c19610SAn-Cheng Huang                 case 8:
220194c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
220294c19610SAn-Cheng Huang                         goto done_syscall;
220394c19610SAn-Cheng Huang                     }
220494c19610SAn-Cheng Huang                 case 7:
220594c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
220694c19610SAn-Cheng Huang                         goto done_syscall;
220794c19610SAn-Cheng Huang                     }
220894c19610SAn-Cheng Huang                 case 6:
220994c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
221094c19610SAn-Cheng Huang                         goto done_syscall;
221194c19610SAn-Cheng Huang                     }
221294c19610SAn-Cheng Huang                 case 5:
221394c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
221494c19610SAn-Cheng Huang                         goto done_syscall;
221594c19610SAn-Cheng Huang                     }
2216388bb21aSths                 default:
2217388bb21aSths                     break;
2218048f6b4dSbellard                 }
2219b5dc7732Sths                 ret = do_syscall(env, env->active_tc.gpr[2],
2220b5dc7732Sths                                  env->active_tc.gpr[4],
2221b5dc7732Sths                                  env->active_tc.gpr[5],
2222b5dc7732Sths                                  env->active_tc.gpr[6],
2223b5dc7732Sths                                  env->active_tc.gpr[7],
22245945cfcbSPeter Maydell                                  arg5, arg6, arg7, arg8);
2225048f6b4dSbellard             }
222694c19610SAn-Cheng Huang done_syscall:
22270b1bcb00Spbrook             if (ret == -TARGET_QEMU_ESIGRETURN) {
22280b1bcb00Spbrook                 /* Returning from a successful sigreturn syscall.
22290b1bcb00Spbrook                    Avoid clobbering register state.  */
22300b1bcb00Spbrook                 break;
22310b1bcb00Spbrook             }
2232048f6b4dSbellard             if ((unsigned int)ret >= (unsigned int)(-1133)) {
2233b5dc7732Sths                 env->active_tc.gpr[7] = 1; /* error flag */
2234048f6b4dSbellard                 ret = -ret;
2235048f6b4dSbellard             } else {
2236b5dc7732Sths                 env->active_tc.gpr[7] = 0; /* error flag */
2237388bb21aSths             }
2238b5dc7732Sths             env->active_tc.gpr[2] = ret;
2239048f6b4dSbellard             break;
2240ca7c2b1bSths         case EXCP_TLBL:
2241ca7c2b1bSths         case EXCP_TLBS:
2242e6e5bd2dSWesley W. Terpstra         case EXCP_AdEL:
2243e6e5bd2dSWesley W. Terpstra         case EXCP_AdES:
2244e4474235Spbrook             info.si_signo = TARGET_SIGSEGV;
2245e4474235Spbrook             info.si_errno = 0;
2246e4474235Spbrook             /* XXX: check env->error_code */
2247e4474235Spbrook             info.si_code = TARGET_SEGV_MAPERR;
2248e4474235Spbrook             info._sifields._sigfault._addr = env->CP0_BadVAddr;
2249e4474235Spbrook             queue_signal(env, info.si_signo, &info);
2250e4474235Spbrook             break;
22516900e84bSbellard         case EXCP_CpU:
2252048f6b4dSbellard         case EXCP_RI:
2253048f6b4dSbellard             info.si_signo = TARGET_SIGILL;
2254048f6b4dSbellard             info.si_errno = 0;
2255048f6b4dSbellard             info.si_code = 0;
2256624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2257048f6b4dSbellard             break;
2258106ec879Sbellard         case EXCP_INTERRUPT:
2259106ec879Sbellard             /* just indicate that signals should be handled asap */
2260106ec879Sbellard             break;
2261d08b2a28Spbrook         case EXCP_DEBUG:
2262d08b2a28Spbrook             {
2263d08b2a28Spbrook                 int sig;
2264d08b2a28Spbrook 
2265d08b2a28Spbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2266d08b2a28Spbrook                 if (sig)
2267d08b2a28Spbrook                   {
2268d08b2a28Spbrook                     info.si_signo = sig;
2269d08b2a28Spbrook                     info.si_errno = 0;
2270d08b2a28Spbrook                     info.si_code = TARGET_TRAP_BRKPT;
2271624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2272d08b2a28Spbrook                   }
2273d08b2a28Spbrook             }
2274d08b2a28Spbrook             break;
2275590bc601SPaul Brook         case EXCP_SC:
2276590bc601SPaul Brook             if (do_store_exclusive(env)) {
2277590bc601SPaul Brook                 info.si_signo = TARGET_SIGSEGV;
2278590bc601SPaul Brook                 info.si_errno = 0;
2279590bc601SPaul Brook                 info.si_code = TARGET_SEGV_MAPERR;
2280590bc601SPaul Brook                 info._sifields._sigfault._addr = env->active_tc.PC;
2281590bc601SPaul Brook                 queue_signal(env, info.si_signo, &info);
2282590bc601SPaul Brook             }
2283590bc601SPaul Brook             break;
2284048f6b4dSbellard         default:
2285048f6b4dSbellard             //        error:
2286048f6b4dSbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2287048f6b4dSbellard                     trapnr);
2288048f6b4dSbellard             cpu_dump_state(env, stderr, fprintf, 0);
2289048f6b4dSbellard             abort();
2290048f6b4dSbellard         }
2291048f6b4dSbellard         process_pending_signals(env);
2292048f6b4dSbellard     }
2293048f6b4dSbellard }
2294048f6b4dSbellard #endif
2295048f6b4dSbellard 
2296d962783eSJia Liu #ifdef TARGET_OPENRISC
2297d962783eSJia Liu 
2298d962783eSJia Liu void cpu_loop(CPUOpenRISCState *env)
2299d962783eSJia Liu {
2300d962783eSJia Liu     int trapnr, gdbsig;
2301d962783eSJia Liu 
2302d962783eSJia Liu     for (;;) {
2303d962783eSJia Liu         trapnr = cpu_exec(env);
2304d962783eSJia Liu         gdbsig = 0;
2305d962783eSJia Liu 
2306d962783eSJia Liu         switch (trapnr) {
2307d962783eSJia Liu         case EXCP_RESET:
2308d962783eSJia Liu             qemu_log("\nReset request, exit, pc is %#x\n", env->pc);
2309d962783eSJia Liu             exit(1);
2310d962783eSJia Liu             break;
2311d962783eSJia Liu         case EXCP_BUSERR:
2312d962783eSJia Liu             qemu_log("\nBus error, exit, pc is %#x\n", env->pc);
2313d962783eSJia Liu             gdbsig = SIGBUS;
2314d962783eSJia Liu             break;
2315d962783eSJia Liu         case EXCP_DPF:
2316d962783eSJia Liu         case EXCP_IPF:
2317d962783eSJia Liu             cpu_dump_state(env, stderr, fprintf, 0);
2318d962783eSJia Liu             gdbsig = TARGET_SIGSEGV;
2319d962783eSJia Liu             break;
2320d962783eSJia Liu         case EXCP_TICK:
2321d962783eSJia Liu             qemu_log("\nTick time interrupt pc is %#x\n", env->pc);
2322d962783eSJia Liu             break;
2323d962783eSJia Liu         case EXCP_ALIGN:
2324d962783eSJia Liu             qemu_log("\nAlignment pc is %#x\n", env->pc);
2325d962783eSJia Liu             gdbsig = SIGBUS;
2326d962783eSJia Liu             break;
2327d962783eSJia Liu         case EXCP_ILLEGAL:
2328d962783eSJia Liu             qemu_log("\nIllegal instructionpc is %#x\n", env->pc);
2329d962783eSJia Liu             gdbsig = SIGILL;
2330d962783eSJia Liu             break;
2331d962783eSJia Liu         case EXCP_INT:
2332d962783eSJia Liu             qemu_log("\nExternal interruptpc is %#x\n", env->pc);
2333d962783eSJia Liu             break;
2334d962783eSJia Liu         case EXCP_DTLBMISS:
2335d962783eSJia Liu         case EXCP_ITLBMISS:
2336d962783eSJia Liu             qemu_log("\nTLB miss\n");
2337d962783eSJia Liu             break;
2338d962783eSJia Liu         case EXCP_RANGE:
2339d962783eSJia Liu             qemu_log("\nRange\n");
2340d962783eSJia Liu             gdbsig = SIGSEGV;
2341d962783eSJia Liu             break;
2342d962783eSJia Liu         case EXCP_SYSCALL:
2343d962783eSJia Liu             env->pc += 4;   /* 0xc00; */
2344d962783eSJia Liu             env->gpr[11] = do_syscall(env,
2345d962783eSJia Liu                                       env->gpr[11], /* return value       */
2346d962783eSJia Liu                                       env->gpr[3],  /* r3 - r7 are params */
2347d962783eSJia Liu                                       env->gpr[4],
2348d962783eSJia Liu                                       env->gpr[5],
2349d962783eSJia Liu                                       env->gpr[6],
2350d962783eSJia Liu                                       env->gpr[7],
2351d962783eSJia Liu                                       env->gpr[8], 0, 0);
2352d962783eSJia Liu             break;
2353d962783eSJia Liu         case EXCP_FPE:
2354d962783eSJia Liu             qemu_log("\nFloating point error\n");
2355d962783eSJia Liu             break;
2356d962783eSJia Liu         case EXCP_TRAP:
2357d962783eSJia Liu             qemu_log("\nTrap\n");
2358d962783eSJia Liu             gdbsig = SIGTRAP;
2359d962783eSJia Liu             break;
2360d962783eSJia Liu         case EXCP_NR:
2361d962783eSJia Liu             qemu_log("\nNR\n");
2362d962783eSJia Liu             break;
2363d962783eSJia Liu         default:
2364d962783eSJia Liu             qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n",
2365d962783eSJia Liu                      trapnr);
2366d962783eSJia Liu             cpu_dump_state(env, stderr, fprintf, 0);
2367d962783eSJia Liu             gdbsig = TARGET_SIGILL;
2368d962783eSJia Liu             break;
2369d962783eSJia Liu         }
2370d962783eSJia Liu         if (gdbsig) {
2371d962783eSJia Liu             gdb_handlesig(env, gdbsig);
2372d962783eSJia Liu             if (gdbsig != TARGET_SIGTRAP) {
2373d962783eSJia Liu                 exit(1);
2374d962783eSJia Liu             }
2375d962783eSJia Liu         }
2376d962783eSJia Liu 
2377d962783eSJia Liu         process_pending_signals(env);
2378d962783eSJia Liu     }
2379d962783eSJia Liu }
2380d962783eSJia Liu 
2381d962783eSJia Liu #endif /* TARGET_OPENRISC */
2382d962783eSJia Liu 
2383fdf9b3e8Sbellard #ifdef TARGET_SH4
238405390248SAndreas Färber void cpu_loop(CPUSH4State *env)
2385fdf9b3e8Sbellard {
2386fdf9b3e8Sbellard     int trapnr, ret;
2387c227f099SAnthony Liguori     target_siginfo_t info;
2388fdf9b3e8Sbellard 
2389fdf9b3e8Sbellard     while (1) {
2390fdf9b3e8Sbellard         trapnr = cpu_sh4_exec (env);
2391fdf9b3e8Sbellard 
2392fdf9b3e8Sbellard         switch (trapnr) {
2393fdf9b3e8Sbellard         case 0x160:
23940b6d3ae0Saurel32             env->pc += 2;
2395fdf9b3e8Sbellard             ret = do_syscall(env,
23969c2a9ea1Spbrook                              env->gregs[3],
23979c2a9ea1Spbrook                              env->gregs[4],
23989c2a9ea1Spbrook                              env->gregs[5],
23999c2a9ea1Spbrook                              env->gregs[6],
24009c2a9ea1Spbrook                              env->gregs[7],
24019c2a9ea1Spbrook                              env->gregs[0],
24025945cfcbSPeter Maydell                              env->gregs[1],
24035945cfcbSPeter Maydell                              0, 0);
24049c2a9ea1Spbrook             env->gregs[0] = ret;
2405fdf9b3e8Sbellard             break;
2406c3b5bc8aSths         case EXCP_INTERRUPT:
2407c3b5bc8aSths             /* just indicate that signals should be handled asap */
2408c3b5bc8aSths             break;
2409355fb23dSpbrook         case EXCP_DEBUG:
2410355fb23dSpbrook             {
2411355fb23dSpbrook                 int sig;
2412355fb23dSpbrook 
2413355fb23dSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2414355fb23dSpbrook                 if (sig)
2415355fb23dSpbrook                   {
2416355fb23dSpbrook                     info.si_signo = sig;
2417355fb23dSpbrook                     info.si_errno = 0;
2418355fb23dSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2419624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2420355fb23dSpbrook                   }
2421355fb23dSpbrook             }
2422355fb23dSpbrook             break;
2423c3b5bc8aSths 	case 0xa0:
2424c3b5bc8aSths 	case 0xc0:
2425c3b5bc8aSths             info.si_signo = SIGSEGV;
2426c3b5bc8aSths             info.si_errno = 0;
2427c3b5bc8aSths             info.si_code = TARGET_SEGV_MAPERR;
2428c3b5bc8aSths             info._sifields._sigfault._addr = env->tea;
2429624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2430c3b5bc8aSths 	    break;
2431c3b5bc8aSths 
2432fdf9b3e8Sbellard         default:
2433fdf9b3e8Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
2434fdf9b3e8Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
2435fdf9b3e8Sbellard             exit (1);
2436fdf9b3e8Sbellard         }
2437fdf9b3e8Sbellard         process_pending_signals (env);
2438fdf9b3e8Sbellard     }
2439fdf9b3e8Sbellard }
2440fdf9b3e8Sbellard #endif
2441fdf9b3e8Sbellard 
244248733d19Sths #ifdef TARGET_CRIS
244305390248SAndreas Färber void cpu_loop(CPUCRISState *env)
244448733d19Sths {
244548733d19Sths     int trapnr, ret;
2446c227f099SAnthony Liguori     target_siginfo_t info;
244748733d19Sths 
244848733d19Sths     while (1) {
244948733d19Sths         trapnr = cpu_cris_exec (env);
245048733d19Sths         switch (trapnr) {
245148733d19Sths         case 0xaa:
245248733d19Sths             {
245348733d19Sths                 info.si_signo = SIGSEGV;
245448733d19Sths                 info.si_errno = 0;
245548733d19Sths                 /* XXX: check env->error_code */
245648733d19Sths                 info.si_code = TARGET_SEGV_MAPERR;
2457e00c1e71Sedgar_igl                 info._sifields._sigfault._addr = env->pregs[PR_EDA];
2458624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
245948733d19Sths             }
246048733d19Sths             break;
2461b6d3abdaSedgar_igl 	case EXCP_INTERRUPT:
2462b6d3abdaSedgar_igl 	  /* just indicate that signals should be handled asap */
2463b6d3abdaSedgar_igl 	  break;
246448733d19Sths         case EXCP_BREAK:
246548733d19Sths             ret = do_syscall(env,
246648733d19Sths                              env->regs[9],
246748733d19Sths                              env->regs[10],
246848733d19Sths                              env->regs[11],
246948733d19Sths                              env->regs[12],
247048733d19Sths                              env->regs[13],
247148733d19Sths                              env->pregs[7],
24725945cfcbSPeter Maydell                              env->pregs[11],
24735945cfcbSPeter Maydell                              0, 0);
247448733d19Sths             env->regs[10] = ret;
247548733d19Sths             break;
247648733d19Sths         case EXCP_DEBUG:
247748733d19Sths             {
247848733d19Sths                 int sig;
247948733d19Sths 
248048733d19Sths                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
248148733d19Sths                 if (sig)
248248733d19Sths                   {
248348733d19Sths                     info.si_signo = sig;
248448733d19Sths                     info.si_errno = 0;
248548733d19Sths                     info.si_code = TARGET_TRAP_BRKPT;
2486624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
248748733d19Sths                   }
248848733d19Sths             }
248948733d19Sths             break;
249048733d19Sths         default:
249148733d19Sths             printf ("Unhandled trap: 0x%x\n", trapnr);
249248733d19Sths             cpu_dump_state(env, stderr, fprintf, 0);
249348733d19Sths             exit (1);
249448733d19Sths         }
249548733d19Sths         process_pending_signals (env);
249648733d19Sths     }
249748733d19Sths }
249848733d19Sths #endif
249948733d19Sths 
2500b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
250105390248SAndreas Färber void cpu_loop(CPUMBState *env)
2502b779e29eSEdgar E. Iglesias {
2503b779e29eSEdgar E. Iglesias     int trapnr, ret;
2504c227f099SAnthony Liguori     target_siginfo_t info;
2505b779e29eSEdgar E. Iglesias 
2506b779e29eSEdgar E. Iglesias     while (1) {
2507b779e29eSEdgar E. Iglesias         trapnr = cpu_mb_exec (env);
2508b779e29eSEdgar E. Iglesias         switch (trapnr) {
2509b779e29eSEdgar E. Iglesias         case 0xaa:
2510b779e29eSEdgar E. Iglesias             {
2511b779e29eSEdgar E. Iglesias                 info.si_signo = SIGSEGV;
2512b779e29eSEdgar E. Iglesias                 info.si_errno = 0;
2513b779e29eSEdgar E. Iglesias                 /* XXX: check env->error_code */
2514b779e29eSEdgar E. Iglesias                 info.si_code = TARGET_SEGV_MAPERR;
2515b779e29eSEdgar E. Iglesias                 info._sifields._sigfault._addr = 0;
2516b779e29eSEdgar E. Iglesias                 queue_signal(env, info.si_signo, &info);
2517b779e29eSEdgar E. Iglesias             }
2518b779e29eSEdgar E. Iglesias             break;
2519b779e29eSEdgar E. Iglesias 	case EXCP_INTERRUPT:
2520b779e29eSEdgar E. Iglesias 	  /* just indicate that signals should be handled asap */
2521b779e29eSEdgar E. Iglesias 	  break;
2522b779e29eSEdgar E. Iglesias         case EXCP_BREAK:
2523b779e29eSEdgar E. Iglesias             /* Return address is 4 bytes after the call.  */
2524b779e29eSEdgar E. Iglesias             env->regs[14] += 4;
2525b779e29eSEdgar E. Iglesias             ret = do_syscall(env,
2526b779e29eSEdgar E. Iglesias                              env->regs[12],
2527b779e29eSEdgar E. Iglesias                              env->regs[5],
2528b779e29eSEdgar E. Iglesias                              env->regs[6],
2529b779e29eSEdgar E. Iglesias                              env->regs[7],
2530b779e29eSEdgar E. Iglesias                              env->regs[8],
2531b779e29eSEdgar E. Iglesias                              env->regs[9],
25325945cfcbSPeter Maydell                              env->regs[10],
25335945cfcbSPeter Maydell                              0, 0);
2534b779e29eSEdgar E. Iglesias             env->regs[3] = ret;
2535b779e29eSEdgar E. Iglesias             env->sregs[SR_PC] = env->regs[14];
2536b779e29eSEdgar E. Iglesias             break;
2537b76da7e3SEdgar E. Iglesias         case EXCP_HW_EXCP:
2538b76da7e3SEdgar E. Iglesias             env->regs[17] = env->sregs[SR_PC] + 4;
2539b76da7e3SEdgar E. Iglesias             if (env->iflags & D_FLAG) {
2540b76da7e3SEdgar E. Iglesias                 env->sregs[SR_ESR] |= 1 << 12;
2541b76da7e3SEdgar E. Iglesias                 env->sregs[SR_PC] -= 4;
2542b76da7e3SEdgar E. Iglesias                 /* FIXME: if branch was immed, replay the imm as well.  */
2543b76da7e3SEdgar E. Iglesias             }
2544b76da7e3SEdgar E. Iglesias 
2545b76da7e3SEdgar E. Iglesias             env->iflags &= ~(IMM_FLAG | D_FLAG);
2546b76da7e3SEdgar E. Iglesias 
2547b76da7e3SEdgar E. Iglesias             switch (env->sregs[SR_ESR] & 31) {
254822a78d64SEdgar E. Iglesias                 case ESR_EC_DIVZERO:
254922a78d64SEdgar E. Iglesias                     info.si_signo = SIGFPE;
255022a78d64SEdgar E. Iglesias                     info.si_errno = 0;
255122a78d64SEdgar E. Iglesias                     info.si_code = TARGET_FPE_FLTDIV;
255222a78d64SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
255322a78d64SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
255422a78d64SEdgar E. Iglesias                     break;
2555b76da7e3SEdgar E. Iglesias                 case ESR_EC_FPU:
2556b76da7e3SEdgar E. Iglesias                     info.si_signo = SIGFPE;
2557b76da7e3SEdgar E. Iglesias                     info.si_errno = 0;
2558b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_IO) {
2559b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTINV;
2560b76da7e3SEdgar E. Iglesias                     }
2561b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_DZ) {
2562b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTDIV;
2563b76da7e3SEdgar E. Iglesias                     }
2564b76da7e3SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
2565b76da7e3SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2566b76da7e3SEdgar E. Iglesias                     break;
2567b76da7e3SEdgar E. Iglesias                 default:
2568b76da7e3SEdgar E. Iglesias                     printf ("Unhandled hw-exception: 0x%x\n",
25692e42d52dSEdgar E. Iglesias                             env->sregs[SR_ESR] & ESR_EC_MASK);
2570b76da7e3SEdgar E. Iglesias                     cpu_dump_state(env, stderr, fprintf, 0);
2571b76da7e3SEdgar E. Iglesias                     exit (1);
2572b76da7e3SEdgar E. Iglesias                     break;
2573b76da7e3SEdgar E. Iglesias             }
2574b76da7e3SEdgar E. Iglesias             break;
2575b779e29eSEdgar E. Iglesias         case EXCP_DEBUG:
2576b779e29eSEdgar E. Iglesias             {
2577b779e29eSEdgar E. Iglesias                 int sig;
2578b779e29eSEdgar E. Iglesias 
2579b779e29eSEdgar E. Iglesias                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2580b779e29eSEdgar E. Iglesias                 if (sig)
2581b779e29eSEdgar E. Iglesias                   {
2582b779e29eSEdgar E. Iglesias                     info.si_signo = sig;
2583b779e29eSEdgar E. Iglesias                     info.si_errno = 0;
2584b779e29eSEdgar E. Iglesias                     info.si_code = TARGET_TRAP_BRKPT;
2585b779e29eSEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2586b779e29eSEdgar E. Iglesias                   }
2587b779e29eSEdgar E. Iglesias             }
2588b779e29eSEdgar E. Iglesias             break;
2589b779e29eSEdgar E. Iglesias         default:
2590b779e29eSEdgar E. Iglesias             printf ("Unhandled trap: 0x%x\n", trapnr);
2591b779e29eSEdgar E. Iglesias             cpu_dump_state(env, stderr, fprintf, 0);
2592b779e29eSEdgar E. Iglesias             exit (1);
2593b779e29eSEdgar E. Iglesias         }
2594b779e29eSEdgar E. Iglesias         process_pending_signals (env);
2595b779e29eSEdgar E. Iglesias     }
2596b779e29eSEdgar E. Iglesias }
2597b779e29eSEdgar E. Iglesias #endif
2598b779e29eSEdgar E. Iglesias 
2599e6e5906bSpbrook #ifdef TARGET_M68K
2600e6e5906bSpbrook 
2601e6e5906bSpbrook void cpu_loop(CPUM68KState *env)
2602e6e5906bSpbrook {
2603e6e5906bSpbrook     int trapnr;
2604e6e5906bSpbrook     unsigned int n;
2605c227f099SAnthony Liguori     target_siginfo_t info;
2606e6e5906bSpbrook     TaskState *ts = env->opaque;
2607e6e5906bSpbrook 
2608e6e5906bSpbrook     for(;;) {
2609e6e5906bSpbrook         trapnr = cpu_m68k_exec(env);
2610e6e5906bSpbrook         switch(trapnr) {
2611e6e5906bSpbrook         case EXCP_ILLEGAL:
2612e6e5906bSpbrook             {
2613e6e5906bSpbrook                 if (ts->sim_syscalls) {
2614e6e5906bSpbrook                     uint16_t nr;
2615e6e5906bSpbrook                     nr = lduw(env->pc + 2);
2616e6e5906bSpbrook                     env->pc += 4;
2617e6e5906bSpbrook                     do_m68k_simcall(env, nr);
2618e6e5906bSpbrook                 } else {
2619e6e5906bSpbrook                     goto do_sigill;
2620e6e5906bSpbrook                 }
2621e6e5906bSpbrook             }
2622e6e5906bSpbrook             break;
2623a87295e8Spbrook         case EXCP_HALT_INSN:
2624e6e5906bSpbrook             /* Semihosing syscall.  */
2625a87295e8Spbrook             env->pc += 4;
2626e6e5906bSpbrook             do_m68k_semihosting(env, env->dregs[0]);
2627e6e5906bSpbrook             break;
2628e6e5906bSpbrook         case EXCP_LINEA:
2629e6e5906bSpbrook         case EXCP_LINEF:
2630e6e5906bSpbrook         case EXCP_UNSUPPORTED:
2631e6e5906bSpbrook         do_sigill:
2632e6e5906bSpbrook             info.si_signo = SIGILL;
2633e6e5906bSpbrook             info.si_errno = 0;
2634e6e5906bSpbrook             info.si_code = TARGET_ILL_ILLOPN;
2635e6e5906bSpbrook             info._sifields._sigfault._addr = env->pc;
2636624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2637e6e5906bSpbrook             break;
2638e6e5906bSpbrook         case EXCP_TRAP0:
2639e6e5906bSpbrook             {
2640e6e5906bSpbrook                 ts->sim_syscalls = 0;
2641e6e5906bSpbrook                 n = env->dregs[0];
2642e6e5906bSpbrook                 env->pc += 2;
2643e6e5906bSpbrook                 env->dregs[0] = do_syscall(env,
2644e6e5906bSpbrook                                           n,
2645e6e5906bSpbrook                                           env->dregs[1],
2646e6e5906bSpbrook                                           env->dregs[2],
2647e6e5906bSpbrook                                           env->dregs[3],
2648e6e5906bSpbrook                                           env->dregs[4],
2649e6e5906bSpbrook                                           env->dregs[5],
26505945cfcbSPeter Maydell                                           env->aregs[0],
26515945cfcbSPeter Maydell                                           0, 0);
2652e6e5906bSpbrook             }
2653e6e5906bSpbrook             break;
2654e6e5906bSpbrook         case EXCP_INTERRUPT:
2655e6e5906bSpbrook             /* just indicate that signals should be handled asap */
2656e6e5906bSpbrook             break;
2657e6e5906bSpbrook         case EXCP_ACCESS:
2658e6e5906bSpbrook             {
2659e6e5906bSpbrook                 info.si_signo = SIGSEGV;
2660e6e5906bSpbrook                 info.si_errno = 0;
2661e6e5906bSpbrook                 /* XXX: check env->error_code */
2662e6e5906bSpbrook                 info.si_code = TARGET_SEGV_MAPERR;
2663e6e5906bSpbrook                 info._sifields._sigfault._addr = env->mmu.ar;
2664624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
2665e6e5906bSpbrook             }
2666e6e5906bSpbrook             break;
2667e6e5906bSpbrook         case EXCP_DEBUG:
2668e6e5906bSpbrook             {
2669e6e5906bSpbrook                 int sig;
2670e6e5906bSpbrook 
2671e6e5906bSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2672e6e5906bSpbrook                 if (sig)
2673e6e5906bSpbrook                   {
2674e6e5906bSpbrook                     info.si_signo = sig;
2675e6e5906bSpbrook                     info.si_errno = 0;
2676e6e5906bSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2677624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2678e6e5906bSpbrook                   }
2679e6e5906bSpbrook             }
2680e6e5906bSpbrook             break;
2681e6e5906bSpbrook         default:
2682e6e5906bSpbrook             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2683e6e5906bSpbrook                     trapnr);
2684e6e5906bSpbrook             cpu_dump_state(env, stderr, fprintf, 0);
2685e6e5906bSpbrook             abort();
2686e6e5906bSpbrook         }
2687e6e5906bSpbrook         process_pending_signals(env);
2688e6e5906bSpbrook     }
2689e6e5906bSpbrook }
2690e6e5906bSpbrook #endif /* TARGET_M68K */
2691e6e5906bSpbrook 
26927a3148a9Sj_mayer #ifdef TARGET_ALPHA
26936910b8f6SRichard Henderson static void do_store_exclusive(CPUAlphaState *env, int reg, int quad)
26946910b8f6SRichard Henderson {
26956910b8f6SRichard Henderson     target_ulong addr, val, tmp;
26966910b8f6SRichard Henderson     target_siginfo_t info;
26976910b8f6SRichard Henderson     int ret = 0;
26986910b8f6SRichard Henderson 
26996910b8f6SRichard Henderson     addr = env->lock_addr;
27006910b8f6SRichard Henderson     tmp = env->lock_st_addr;
27016910b8f6SRichard Henderson     env->lock_addr = -1;
27026910b8f6SRichard Henderson     env->lock_st_addr = 0;
27036910b8f6SRichard Henderson 
27046910b8f6SRichard Henderson     start_exclusive();
27056910b8f6SRichard Henderson     mmap_lock();
27066910b8f6SRichard Henderson 
27076910b8f6SRichard Henderson     if (addr == tmp) {
27086910b8f6SRichard Henderson         if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
27096910b8f6SRichard Henderson             goto do_sigsegv;
27106910b8f6SRichard Henderson         }
27116910b8f6SRichard Henderson 
27126910b8f6SRichard Henderson         if (val == env->lock_value) {
27136910b8f6SRichard Henderson             tmp = env->ir[reg];
27146910b8f6SRichard Henderson             if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) {
27156910b8f6SRichard Henderson                 goto do_sigsegv;
27166910b8f6SRichard Henderson             }
27176910b8f6SRichard Henderson             ret = 1;
27186910b8f6SRichard Henderson         }
27196910b8f6SRichard Henderson     }
27206910b8f6SRichard Henderson     env->ir[reg] = ret;
27216910b8f6SRichard Henderson     env->pc += 4;
27226910b8f6SRichard Henderson 
27236910b8f6SRichard Henderson     mmap_unlock();
27246910b8f6SRichard Henderson     end_exclusive();
27256910b8f6SRichard Henderson     return;
27266910b8f6SRichard Henderson 
27276910b8f6SRichard Henderson  do_sigsegv:
27286910b8f6SRichard Henderson     mmap_unlock();
27296910b8f6SRichard Henderson     end_exclusive();
27306910b8f6SRichard Henderson 
27316910b8f6SRichard Henderson     info.si_signo = TARGET_SIGSEGV;
27326910b8f6SRichard Henderson     info.si_errno = 0;
27336910b8f6SRichard Henderson     info.si_code = TARGET_SEGV_MAPERR;
27346910b8f6SRichard Henderson     info._sifields._sigfault._addr = addr;
27356910b8f6SRichard Henderson     queue_signal(env, TARGET_SIGSEGV, &info);
27366910b8f6SRichard Henderson }
27376910b8f6SRichard Henderson 
273805390248SAndreas Färber void cpu_loop(CPUAlphaState *env)
27397a3148a9Sj_mayer {
2740e96efcfcSj_mayer     int trapnr;
2741c227f099SAnthony Liguori     target_siginfo_t info;
27426049f4f8SRichard Henderson     abi_long sysret;
27437a3148a9Sj_mayer 
27447a3148a9Sj_mayer     while (1) {
27457a3148a9Sj_mayer         trapnr = cpu_alpha_exec (env);
27467a3148a9Sj_mayer 
2747ac316ca4SRichard Henderson         /* All of the traps imply a transition through PALcode, which
2748ac316ca4SRichard Henderson            implies an REI instruction has been executed.  Which means
2749ac316ca4SRichard Henderson            that the intr_flag should be cleared.  */
2750ac316ca4SRichard Henderson         env->intr_flag = 0;
2751ac316ca4SRichard Henderson 
27527a3148a9Sj_mayer         switch (trapnr) {
27537a3148a9Sj_mayer         case EXCP_RESET:
27547a3148a9Sj_mayer             fprintf(stderr, "Reset requested. Exit\n");
27557a3148a9Sj_mayer             exit(1);
27567a3148a9Sj_mayer             break;
27577a3148a9Sj_mayer         case EXCP_MCHK:
27587a3148a9Sj_mayer             fprintf(stderr, "Machine check exception. Exit\n");
27597a3148a9Sj_mayer             exit(1);
27607a3148a9Sj_mayer             break;
276107b6c13bSRichard Henderson         case EXCP_SMP_INTERRUPT:
276207b6c13bSRichard Henderson         case EXCP_CLK_INTERRUPT:
276307b6c13bSRichard Henderson         case EXCP_DEV_INTERRUPT:
27647a3148a9Sj_mayer             fprintf(stderr, "External interrupt. Exit\n");
27657a3148a9Sj_mayer             exit(1);
27667a3148a9Sj_mayer             break;
276707b6c13bSRichard Henderson         case EXCP_MMFAULT:
27686910b8f6SRichard Henderson             env->lock_addr = -1;
27696049f4f8SRichard Henderson             info.si_signo = TARGET_SIGSEGV;
27706049f4f8SRichard Henderson             info.si_errno = 0;
2771129d8aa5SRichard Henderson             info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
27720be1d07cSRichard Henderson                             ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
2773129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
27746049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
27757a3148a9Sj_mayer             break;
27767a3148a9Sj_mayer         case EXCP_UNALIGN:
27776910b8f6SRichard Henderson             env->lock_addr = -1;
27786049f4f8SRichard Henderson             info.si_signo = TARGET_SIGBUS;
27796049f4f8SRichard Henderson             info.si_errno = 0;
27806049f4f8SRichard Henderson             info.si_code = TARGET_BUS_ADRALN;
2781129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
27826049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
27837a3148a9Sj_mayer             break;
27847a3148a9Sj_mayer         case EXCP_OPCDEC:
27856049f4f8SRichard Henderson         do_sigill:
27866910b8f6SRichard Henderson             env->lock_addr = -1;
27876049f4f8SRichard Henderson             info.si_signo = TARGET_SIGILL;
27886049f4f8SRichard Henderson             info.si_errno = 0;
27896049f4f8SRichard Henderson             info.si_code = TARGET_ILL_ILLOPC;
27906049f4f8SRichard Henderson             info._sifields._sigfault._addr = env->pc;
27916049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
27927a3148a9Sj_mayer             break;
279307b6c13bSRichard Henderson         case EXCP_ARITH:
279407b6c13bSRichard Henderson             env->lock_addr = -1;
279507b6c13bSRichard Henderson             info.si_signo = TARGET_SIGFPE;
279607b6c13bSRichard Henderson             info.si_errno = 0;
279707b6c13bSRichard Henderson             info.si_code = TARGET_FPE_FLTINV;
279807b6c13bSRichard Henderson             info._sifields._sigfault._addr = env->pc;
279907b6c13bSRichard Henderson             queue_signal(env, info.si_signo, &info);
280007b6c13bSRichard Henderson             break;
28017a3148a9Sj_mayer         case EXCP_FEN:
28026049f4f8SRichard Henderson             /* No-op.  Linux simply re-enables the FPU.  */
28037a3148a9Sj_mayer             break;
280407b6c13bSRichard Henderson         case EXCP_CALL_PAL:
28056910b8f6SRichard Henderson             env->lock_addr = -1;
280607b6c13bSRichard Henderson             switch (env->error_code) {
28076049f4f8SRichard Henderson             case 0x80:
28086049f4f8SRichard Henderson                 /* BPT */
28096049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
28106049f4f8SRichard Henderson                 info.si_errno = 0;
28116049f4f8SRichard Henderson                 info.si_code = TARGET_TRAP_BRKPT;
28126049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
28136049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
28146049f4f8SRichard Henderson                 break;
28156049f4f8SRichard Henderson             case 0x81:
28166049f4f8SRichard Henderson                 /* BUGCHK */
28176049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
28186049f4f8SRichard Henderson                 info.si_errno = 0;
28196049f4f8SRichard Henderson                 info.si_code = 0;
28206049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
28216049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
28226049f4f8SRichard Henderson                 break;
28236049f4f8SRichard Henderson             case 0x83:
28246049f4f8SRichard Henderson                 /* CALLSYS */
28256049f4f8SRichard Henderson                 trapnr = env->ir[IR_V0];
28266049f4f8SRichard Henderson                 sysret = do_syscall(env, trapnr,
28276049f4f8SRichard Henderson                                     env->ir[IR_A0], env->ir[IR_A1],
28286049f4f8SRichard Henderson                                     env->ir[IR_A2], env->ir[IR_A3],
28295945cfcbSPeter Maydell                                     env->ir[IR_A4], env->ir[IR_A5],
28305945cfcbSPeter Maydell                                     0, 0);
2831a5b3b13bSRichard Henderson                 if (trapnr == TARGET_NR_sigreturn
2832a5b3b13bSRichard Henderson                     || trapnr == TARGET_NR_rt_sigreturn) {
2833a5b3b13bSRichard Henderson                     break;
2834a5b3b13bSRichard Henderson                 }
2835a5b3b13bSRichard Henderson                 /* Syscall writes 0 to V0 to bypass error check, similar
28360e141977SRichard Henderson                    to how this is handled internal to Linux kernel.
28370e141977SRichard Henderson                    (Ab)use trapnr temporarily as boolean indicating error.  */
28380e141977SRichard Henderson                 trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
28390e141977SRichard Henderson                 env->ir[IR_V0] = (trapnr ? -sysret : sysret);
28400e141977SRichard Henderson                 env->ir[IR_A3] = trapnr;
28416049f4f8SRichard Henderson                 break;
28426049f4f8SRichard Henderson             case 0x86:
28436049f4f8SRichard Henderson                 /* IMB */
28446049f4f8SRichard Henderson                 /* ??? We can probably elide the code using page_unprotect
28456049f4f8SRichard Henderson                    that is checking for self-modifying code.  Instead we
28466049f4f8SRichard Henderson                    could simply call tb_flush here.  Until we work out the
28476049f4f8SRichard Henderson                    changes required to turn off the extra write protection,
28486049f4f8SRichard Henderson                    this can be a no-op.  */
28496049f4f8SRichard Henderson                 break;
28506049f4f8SRichard Henderson             case 0x9E:
28516049f4f8SRichard Henderson                 /* RDUNIQUE */
28526049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
28536049f4f8SRichard Henderson                 abort();
28546049f4f8SRichard Henderson             case 0x9F:
28556049f4f8SRichard Henderson                 /* WRUNIQUE */
28566049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
28576049f4f8SRichard Henderson                 abort();
28586049f4f8SRichard Henderson             case 0xAA:
28596049f4f8SRichard Henderson                 /* GENTRAP */
28606049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGFPE;
28616049f4f8SRichard Henderson                 switch (env->ir[IR_A0]) {
28626049f4f8SRichard Henderson                 case TARGET_GEN_INTOVF:
28636049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTOVF;
28646049f4f8SRichard Henderson                     break;
28656049f4f8SRichard Henderson                 case TARGET_GEN_INTDIV:
28666049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTDIV;
28676049f4f8SRichard Henderson                     break;
28686049f4f8SRichard Henderson                 case TARGET_GEN_FLTOVF:
28696049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTOVF;
28706049f4f8SRichard Henderson                     break;
28716049f4f8SRichard Henderson                 case TARGET_GEN_FLTUND:
28726049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTUND;
28736049f4f8SRichard Henderson                     break;
28746049f4f8SRichard Henderson                 case TARGET_GEN_FLTINV:
28756049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTINV;
28766049f4f8SRichard Henderson                     break;
28776049f4f8SRichard Henderson                 case TARGET_GEN_FLTINE:
28786049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTRES;
28796049f4f8SRichard Henderson                     break;
28806049f4f8SRichard Henderson                 case TARGET_GEN_ROPRAND:
28816049f4f8SRichard Henderson                     info.si_code = 0;
28826049f4f8SRichard Henderson                     break;
28836049f4f8SRichard Henderson                 default:
28846049f4f8SRichard Henderson                     info.si_signo = TARGET_SIGTRAP;
28856049f4f8SRichard Henderson                     info.si_code = 0;
28866049f4f8SRichard Henderson                     break;
28876049f4f8SRichard Henderson                 }
28886049f4f8SRichard Henderson                 info.si_errno = 0;
28896049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
28906049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
28916049f4f8SRichard Henderson                 break;
28926049f4f8SRichard Henderson             default:
28936049f4f8SRichard Henderson                 goto do_sigill;
28946049f4f8SRichard Henderson             }
28957a3148a9Sj_mayer             break;
28967a3148a9Sj_mayer         case EXCP_DEBUG:
28976049f4f8SRichard Henderson             info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
28986049f4f8SRichard Henderson             if (info.si_signo) {
28996910b8f6SRichard Henderson                 env->lock_addr = -1;
29007a3148a9Sj_mayer                 info.si_errno = 0;
29017a3148a9Sj_mayer                 info.si_code = TARGET_TRAP_BRKPT;
2902624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
29037a3148a9Sj_mayer             }
29047a3148a9Sj_mayer             break;
29056910b8f6SRichard Henderson         case EXCP_STL_C:
29066910b8f6SRichard Henderson         case EXCP_STQ_C:
29076910b8f6SRichard Henderson             do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
29086910b8f6SRichard Henderson             break;
2909d0f20495SRichard Henderson         case EXCP_INTERRUPT:
2910d0f20495SRichard Henderson             /* Just indicate that signals should be handled asap.  */
2911d0f20495SRichard Henderson             break;
29127a3148a9Sj_mayer         default:
29137a3148a9Sj_mayer             printf ("Unhandled trap: 0x%x\n", trapnr);
29147a3148a9Sj_mayer             cpu_dump_state(env, stderr, fprintf, 0);
29157a3148a9Sj_mayer             exit (1);
29167a3148a9Sj_mayer         }
29177a3148a9Sj_mayer         process_pending_signals (env);
29187a3148a9Sj_mayer     }
29197a3148a9Sj_mayer }
29207a3148a9Sj_mayer #endif /* TARGET_ALPHA */
29217a3148a9Sj_mayer 
2922a4c075f1SUlrich Hecht #ifdef TARGET_S390X
2923a4c075f1SUlrich Hecht void cpu_loop(CPUS390XState *env)
2924a4c075f1SUlrich Hecht {
2925a4c075f1SUlrich Hecht     int trapnr;
2926a4c075f1SUlrich Hecht     target_siginfo_t info;
2927a4c075f1SUlrich Hecht 
2928a4c075f1SUlrich Hecht     while (1) {
2929a4c075f1SUlrich Hecht         trapnr = cpu_s390x_exec (env);
2930a4c075f1SUlrich Hecht 
2931a4c075f1SUlrich Hecht         switch (trapnr) {
2932a4c075f1SUlrich Hecht         case EXCP_INTERRUPT:
2933a4c075f1SUlrich Hecht             /* just indicate that signals should be handled asap */
2934a4c075f1SUlrich Hecht             break;
2935a4c075f1SUlrich Hecht         case EXCP_DEBUG:
2936a4c075f1SUlrich Hecht             {
2937a4c075f1SUlrich Hecht                 int sig;
2938a4c075f1SUlrich Hecht 
2939a4c075f1SUlrich Hecht                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2940a4c075f1SUlrich Hecht                 if (sig) {
2941a4c075f1SUlrich Hecht                     info.si_signo = sig;
2942a4c075f1SUlrich Hecht                     info.si_errno = 0;
2943a4c075f1SUlrich Hecht                     info.si_code = TARGET_TRAP_BRKPT;
2944a4c075f1SUlrich Hecht                     queue_signal(env, info.si_signo, &info);
2945a4c075f1SUlrich Hecht                 }
2946a4c075f1SUlrich Hecht             }
2947a4c075f1SUlrich Hecht             break;
2948a4c075f1SUlrich Hecht         case EXCP_SVC:
2949a4c075f1SUlrich Hecht             {
2950a4c075f1SUlrich Hecht                 int n = env->int_svc_code;
2951a4c075f1SUlrich Hecht                 if (!n) {
2952a4c075f1SUlrich Hecht                     /* syscalls > 255 */
2953a4c075f1SUlrich Hecht                     n = env->regs[1];
2954a4c075f1SUlrich Hecht                 }
2955a4c075f1SUlrich Hecht                 env->psw.addr += env->int_svc_ilc;
2956a4c075f1SUlrich Hecht                 env->regs[2] = do_syscall(env, n,
2957a4c075f1SUlrich Hecht                            env->regs[2],
2958a4c075f1SUlrich Hecht                            env->regs[3],
2959a4c075f1SUlrich Hecht                            env->regs[4],
2960a4c075f1SUlrich Hecht                            env->regs[5],
2961a4c075f1SUlrich Hecht                            env->regs[6],
29625945cfcbSPeter Maydell                            env->regs[7],
29635945cfcbSPeter Maydell                            0, 0);
2964a4c075f1SUlrich Hecht             }
2965a4c075f1SUlrich Hecht             break;
2966a4c075f1SUlrich Hecht         case EXCP_ADDR:
2967a4c075f1SUlrich Hecht             {
2968a4c075f1SUlrich Hecht                 info.si_signo = SIGSEGV;
2969a4c075f1SUlrich Hecht                 info.si_errno = 0;
2970a4c075f1SUlrich Hecht                 /* XXX: check env->error_code */
2971a4c075f1SUlrich Hecht                 info.si_code = TARGET_SEGV_MAPERR;
2972a4c075f1SUlrich Hecht                 info._sifields._sigfault._addr = env->__excp_addr;
2973a4c075f1SUlrich Hecht                 queue_signal(env, info.si_signo, &info);
2974a4c075f1SUlrich Hecht             }
2975a4c075f1SUlrich Hecht             break;
2976a4c075f1SUlrich Hecht         case EXCP_SPEC:
2977a4c075f1SUlrich Hecht             {
2978a4c075f1SUlrich Hecht                 fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4));
2979a4c075f1SUlrich Hecht                 info.si_signo = SIGILL;
2980a4c075f1SUlrich Hecht                 info.si_errno = 0;
2981a4c075f1SUlrich Hecht                 info.si_code = TARGET_ILL_ILLOPC;
2982a4c075f1SUlrich Hecht                 info._sifields._sigfault._addr = env->__excp_addr;
2983a4c075f1SUlrich Hecht                 queue_signal(env, info.si_signo, &info);
2984a4c075f1SUlrich Hecht             }
2985a4c075f1SUlrich Hecht             break;
2986a4c075f1SUlrich Hecht         default:
2987a4c075f1SUlrich Hecht             printf ("Unhandled trap: 0x%x\n", trapnr);
2988a4c075f1SUlrich Hecht             cpu_dump_state(env, stderr, fprintf, 0);
2989a4c075f1SUlrich Hecht             exit (1);
2990a4c075f1SUlrich Hecht         }
2991a4c075f1SUlrich Hecht         process_pending_signals (env);
2992a4c075f1SUlrich Hecht     }
2993a4c075f1SUlrich Hecht }
2994a4c075f1SUlrich Hecht 
2995a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
2996a4c075f1SUlrich Hecht 
29979349b4f9SAndreas Färber THREAD CPUArchState *thread_env;
299859faf6d6Sbellard 
2999edf8e2afSMika Westerberg void task_settid(TaskState *ts)
3000edf8e2afSMika Westerberg {
3001edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
30022f7bb878SJuan Quintela #ifdef CONFIG_USE_NPTL
3003edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
3004edf8e2afSMika Westerberg #else
3005edf8e2afSMika Westerberg         /* when no threads are used, tid becomes pid */
3006edf8e2afSMika Westerberg         ts->ts_tid = getpid();
3007edf8e2afSMika Westerberg #endif
3008edf8e2afSMika Westerberg     }
3009edf8e2afSMika Westerberg }
3010edf8e2afSMika Westerberg 
3011edf8e2afSMika Westerberg void stop_all_tasks(void)
3012edf8e2afSMika Westerberg {
3013edf8e2afSMika Westerberg     /*
3014edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
3015edf8e2afSMika Westerberg      * handles thread stopping correctly.
3016edf8e2afSMika Westerberg      */
3017edf8e2afSMika Westerberg     start_exclusive();
3018edf8e2afSMika Westerberg }
3019edf8e2afSMika Westerberg 
3020c3a92833Spbrook /* Assumes contents are already zeroed.  */
3021624f7979Spbrook void init_task_state(TaskState *ts)
3022624f7979Spbrook {
3023624f7979Spbrook     int i;
3024624f7979Spbrook 
3025624f7979Spbrook     ts->used = 1;
3026624f7979Spbrook     ts->first_free = ts->sigqueue_table;
3027624f7979Spbrook     for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
3028624f7979Spbrook         ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
3029624f7979Spbrook     }
3030624f7979Spbrook     ts->sigqueue_table[i].next = NULL;
3031624f7979Spbrook }
30329de5e440Sbellard 
3033fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
3034fc9c5412SJohannes Schauer {
3035fc9c5412SJohannes Schauer     usage();
3036fc9c5412SJohannes Schauer }
3037fc9c5412SJohannes Schauer 
3038fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
3039fc9c5412SJohannes Schauer {
3040fc9c5412SJohannes Schauer     int mask;
3041fc9c5412SJohannes Schauer     const CPULogItem *item;
3042fc9c5412SJohannes Schauer 
3043fc9c5412SJohannes Schauer     mask = cpu_str_to_log_mask(arg);
3044fc9c5412SJohannes Schauer     if (!mask) {
3045fc9c5412SJohannes Schauer         printf("Log items (comma separated):\n");
3046fc9c5412SJohannes Schauer         for (item = cpu_log_items; item->mask != 0; item++) {
3047fc9c5412SJohannes Schauer             printf("%-10s %s\n", item->name, item->help);
3048fc9c5412SJohannes Schauer         }
3049fc9c5412SJohannes Schauer         exit(1);
3050fc9c5412SJohannes Schauer     }
3051fc9c5412SJohannes Schauer     cpu_set_log(mask);
3052fc9c5412SJohannes Schauer }
3053fc9c5412SJohannes Schauer 
305450171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
305550171d42S陳韋任 {
305650171d42S陳韋任     cpu_set_log_filename(arg);
305750171d42S陳韋任 }
305850171d42S陳韋任 
3059fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
3060fc9c5412SJohannes Schauer {
3061fc9c5412SJohannes Schauer     char *r, *p, *token;
3062fc9c5412SJohannes Schauer     r = p = strdup(arg);
3063fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
3064fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
3065fc9c5412SJohannes Schauer             usage();
3066fc9c5412SJohannes Schauer         }
3067fc9c5412SJohannes Schauer     }
3068fc9c5412SJohannes Schauer     free(r);
3069fc9c5412SJohannes Schauer }
3070fc9c5412SJohannes Schauer 
3071fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
3072fc9c5412SJohannes Schauer {
3073fc9c5412SJohannes Schauer     char *r, *p, *token;
3074fc9c5412SJohannes Schauer     r = p = strdup(arg);
3075fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
3076fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
3077fc9c5412SJohannes Schauer             usage();
3078fc9c5412SJohannes Schauer         }
3079fc9c5412SJohannes Schauer     }
3080fc9c5412SJohannes Schauer     free(r);
3081fc9c5412SJohannes Schauer }
3082fc9c5412SJohannes Schauer 
3083fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
3084fc9c5412SJohannes Schauer {
3085fc9c5412SJohannes Schauer     argv0 = strdup(arg);
3086fc9c5412SJohannes Schauer }
3087fc9c5412SJohannes Schauer 
3088fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
3089fc9c5412SJohannes Schauer {
3090fc9c5412SJohannes Schauer     char *p;
3091fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
3092fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
3093fc9c5412SJohannes Schauer         usage();
3094fc9c5412SJohannes Schauer     }
3095fc9c5412SJohannes Schauer 
3096fc9c5412SJohannes Schauer     if (*p == 'M') {
3097fc9c5412SJohannes Schauer         guest_stack_size *= 1024 * 1024;
3098fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
3099fc9c5412SJohannes Schauer         guest_stack_size *= 1024;
3100fc9c5412SJohannes Schauer     }
3101fc9c5412SJohannes Schauer }
3102fc9c5412SJohannes Schauer 
3103fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
3104fc9c5412SJohannes Schauer {
3105fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
3106fc9c5412SJohannes Schauer }
3107fc9c5412SJohannes Schauer 
3108fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
3109fc9c5412SJohannes Schauer {
3110fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
3111fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
3112fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
3113fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
3114fc9c5412SJohannes Schauer         exit(1);
3115fc9c5412SJohannes Schauer     }
3116fc9c5412SJohannes Schauer }
3117fc9c5412SJohannes Schauer 
3118fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
3119fc9c5412SJohannes Schauer {
3120fc9c5412SJohannes Schauer     gdbstub_port = atoi(arg);
3121fc9c5412SJohannes Schauer }
3122fc9c5412SJohannes Schauer 
3123fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
3124fc9c5412SJohannes Schauer {
3125fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
3126fc9c5412SJohannes Schauer }
3127fc9c5412SJohannes Schauer 
3128fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
3129fc9c5412SJohannes Schauer {
3130fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
3131c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
3132fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
3133e916cbf8SPeter Maydell #if defined(cpu_list)
3134e916cbf8SPeter Maydell         cpu_list(stdout, &fprintf);
3135fc9c5412SJohannes Schauer #endif
3136fc9c5412SJohannes Schauer         exit(1);
3137fc9c5412SJohannes Schauer     }
3138fc9c5412SJohannes Schauer }
3139fc9c5412SJohannes Schauer 
3140fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE)
3141fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
3142fc9c5412SJohannes Schauer {
3143fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
3144fc9c5412SJohannes Schauer     have_guest_base = 1;
3145fc9c5412SJohannes Schauer }
3146fc9c5412SJohannes Schauer 
3147fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
3148fc9c5412SJohannes Schauer {
3149fc9c5412SJohannes Schauer     char *p;
3150fc9c5412SJohannes Schauer     int shift = 0;
3151fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
3152fc9c5412SJohannes Schauer     switch (*p) {
3153fc9c5412SJohannes Schauer     case 'k':
3154fc9c5412SJohannes Schauer     case 'K':
3155fc9c5412SJohannes Schauer         shift = 10;
3156fc9c5412SJohannes Schauer         break;
3157fc9c5412SJohannes Schauer     case 'M':
3158fc9c5412SJohannes Schauer         shift = 20;
3159fc9c5412SJohannes Schauer         break;
3160fc9c5412SJohannes Schauer     case 'G':
3161fc9c5412SJohannes Schauer         shift = 30;
3162fc9c5412SJohannes Schauer         break;
3163fc9c5412SJohannes Schauer     }
3164fc9c5412SJohannes Schauer     if (shift) {
3165fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
3166fc9c5412SJohannes Schauer         p++;
3167fc9c5412SJohannes Schauer         reserved_va <<= shift;
3168fc9c5412SJohannes Schauer         if (((reserved_va >> shift) != unshifted)
3169fc9c5412SJohannes Schauer #if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
3170fc9c5412SJohannes Schauer             || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
3171fc9c5412SJohannes Schauer #endif
3172fc9c5412SJohannes Schauer             ) {
3173fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
3174fc9c5412SJohannes Schauer             exit(1);
3175fc9c5412SJohannes Schauer         }
3176fc9c5412SJohannes Schauer     }
3177fc9c5412SJohannes Schauer     if (*p) {
3178fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
3179fc9c5412SJohannes Schauer         exit(1);
3180fc9c5412SJohannes Schauer     }
3181fc9c5412SJohannes Schauer }
3182fc9c5412SJohannes Schauer #endif
3183fc9c5412SJohannes Schauer 
3184fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
3185fc9c5412SJohannes Schauer {
3186fc9c5412SJohannes Schauer     singlestep = 1;
3187fc9c5412SJohannes Schauer }
3188fc9c5412SJohannes Schauer 
3189fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
3190fc9c5412SJohannes Schauer {
3191fc9c5412SJohannes Schauer     do_strace = 1;
3192fc9c5412SJohannes Schauer }
3193fc9c5412SJohannes Schauer 
3194fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
3195fc9c5412SJohannes Schauer {
3196fc9c5412SJohannes Schauer     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
3197fc9c5412SJohannes Schauer            ", Copyright (c) 2003-2008 Fabrice Bellard\n");
31981386d4c0SPeter Maydell     exit(0);
3199fc9c5412SJohannes Schauer }
3200fc9c5412SJohannes Schauer 
3201fc9c5412SJohannes Schauer struct qemu_argument {
3202fc9c5412SJohannes Schauer     const char *argv;
3203fc9c5412SJohannes Schauer     const char *env;
3204fc9c5412SJohannes Schauer     bool has_arg;
3205fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
3206fc9c5412SJohannes Schauer     const char *example;
3207fc9c5412SJohannes Schauer     const char *help;
3208fc9c5412SJohannes Schauer };
3209fc9c5412SJohannes Schauer 
321042644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
3211fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
3212fc9c5412SJohannes Schauer      "",           "print this help"},
3213fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
3214fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
3215fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
3216fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
3217fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
3218fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
3219fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
3220c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
3221fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
3222fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
3223fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
3224fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
3225fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
3226fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
3227fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
3228fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
3229fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE)
3230fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
3231fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
3232fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
3233fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
3234fc9c5412SJohannes Schauer #endif
3235fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
3236fc9c5412SJohannes Schauer      "options",    "activate log"},
323750171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
323850171d42S陳韋任      "logfile",     "override default logfile location"},
3239fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
3240fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
3241fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
3242fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
3243fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
3244fc9c5412SJohannes Schauer      "",           "log system calls"},
3245fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
32461386d4c0SPeter Maydell      "",           "display version information and exit"},
3247fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
3248fc9c5412SJohannes Schauer };
3249fc9c5412SJohannes Schauer 
3250fc9c5412SJohannes Schauer static void usage(void)
3251fc9c5412SJohannes Schauer {
325242644ceeSJim Meyering     const struct qemu_argument *arginfo;
3253fc9c5412SJohannes Schauer     int maxarglen;
3254fc9c5412SJohannes Schauer     int maxenvlen;
3255fc9c5412SJohannes Schauer 
3256fc9c5412SJohannes Schauer     printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
3257fc9c5412SJohannes Schauer            "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
3258fc9c5412SJohannes Schauer            "\n"
3259fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
3260fc9c5412SJohannes Schauer            "\n");
3261fc9c5412SJohannes Schauer 
3262fc9c5412SJohannes Schauer     maxarglen = maxenvlen = 0;
3263fc9c5412SJohannes Schauer 
3264fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3265fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
3266fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
3267fc9c5412SJohannes Schauer         }
3268fc9c5412SJohannes Schauer         if (strlen(arginfo->argv) > maxarglen) {
3269fc9c5412SJohannes Schauer             maxarglen = strlen(arginfo->argv);
3270fc9c5412SJohannes Schauer         }
3271fc9c5412SJohannes Schauer     }
3272fc9c5412SJohannes Schauer 
3273fc9c5412SJohannes Schauer     printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
3274fc9c5412SJohannes Schauer             maxenvlen+1, "Env-variable");
3275fc9c5412SJohannes Schauer 
3276fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3277fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
3278fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
3279fc9c5412SJohannes Schauer                     (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
3280fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env, arginfo->help);
3281fc9c5412SJohannes Schauer         } else {
3282fc9c5412SJohannes Schauer             printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
3283fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
3284fc9c5412SJohannes Schauer                     arginfo->help);
3285fc9c5412SJohannes Schauer         }
3286fc9c5412SJohannes Schauer     }
3287fc9c5412SJohannes Schauer 
3288fc9c5412SJohannes Schauer     printf("\n"
3289fc9c5412SJohannes Schauer            "Defaults:\n"
3290fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
3291fc9c5412SJohannes Schauer            "QEMU_STACK_SIZE = %ld byte\n"
3292fc9c5412SJohannes Schauer            "QEMU_LOG        = %s\n",
3293fc9c5412SJohannes Schauer            interp_prefix,
3294fc9c5412SJohannes Schauer            guest_stack_size,
3295fc9c5412SJohannes Schauer            DEBUG_LOGFILE);
3296fc9c5412SJohannes Schauer 
3297fc9c5412SJohannes Schauer     printf("\n"
3298fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
3299fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
3300fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
3301fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
3302fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
3303fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
3304fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
3305fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
3306fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
3307fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
3308fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
3309fc9c5412SJohannes Schauer            "the last change will stay in effect.\n");
3310fc9c5412SJohannes Schauer 
3311fc9c5412SJohannes Schauer     exit(1);
3312fc9c5412SJohannes Schauer }
3313fc9c5412SJohannes Schauer 
3314fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
3315fc9c5412SJohannes Schauer {
3316fc9c5412SJohannes Schauer     const char *r;
3317fc9c5412SJohannes Schauer     int optind;
331842644ceeSJim Meyering     const struct qemu_argument *arginfo;
3319fc9c5412SJohannes Schauer 
3320fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3321fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
3322fc9c5412SJohannes Schauer             continue;
3323fc9c5412SJohannes Schauer         }
3324fc9c5412SJohannes Schauer 
3325fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
3326fc9c5412SJohannes Schauer         if (r != NULL) {
3327fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
3328fc9c5412SJohannes Schauer         }
3329fc9c5412SJohannes Schauer     }
3330fc9c5412SJohannes Schauer 
3331fc9c5412SJohannes Schauer     optind = 1;
3332fc9c5412SJohannes Schauer     for (;;) {
3333fc9c5412SJohannes Schauer         if (optind >= argc) {
3334fc9c5412SJohannes Schauer             break;
3335fc9c5412SJohannes Schauer         }
3336fc9c5412SJohannes Schauer         r = argv[optind];
3337fc9c5412SJohannes Schauer         if (r[0] != '-') {
3338fc9c5412SJohannes Schauer             break;
3339fc9c5412SJohannes Schauer         }
3340fc9c5412SJohannes Schauer         optind++;
3341fc9c5412SJohannes Schauer         r++;
3342fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
3343fc9c5412SJohannes Schauer             break;
3344fc9c5412SJohannes Schauer         }
3345fc9c5412SJohannes Schauer 
3346fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3347fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
33481386d4c0SPeter Maydell                 if (arginfo->has_arg) {
3349fc9c5412SJohannes Schauer                     if (optind >= argc) {
3350fc9c5412SJohannes Schauer                         usage();
3351fc9c5412SJohannes Schauer                     }
3352fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
3353fc9c5412SJohannes Schauer                     optind++;
33541386d4c0SPeter Maydell                 } else {
33551386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
3356fc9c5412SJohannes Schauer                 }
3357fc9c5412SJohannes Schauer                 break;
3358fc9c5412SJohannes Schauer             }
3359fc9c5412SJohannes Schauer         }
3360fc9c5412SJohannes Schauer 
3361fc9c5412SJohannes Schauer         /* no option matched the current argv */
3362fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
3363fc9c5412SJohannes Schauer             usage();
3364fc9c5412SJohannes Schauer         }
3365fc9c5412SJohannes Schauer     }
3366fc9c5412SJohannes Schauer 
3367fc9c5412SJohannes Schauer     if (optind >= argc) {
3368fc9c5412SJohannes Schauer         usage();
3369fc9c5412SJohannes Schauer     }
3370fc9c5412SJohannes Schauer 
3371fc9c5412SJohannes Schauer     filename = argv[optind];
3372fc9c5412SJohannes Schauer     exec_path = argv[optind];
3373fc9c5412SJohannes Schauer 
3374fc9c5412SJohannes Schauer     return optind;
3375fc9c5412SJohannes Schauer }
3376fc9c5412SJohannes Schauer 
3377902b3d5cSmalc int main(int argc, char **argv, char **envp)
337831e31b8aSbellard {
3379c235d738SMatthew Fernandez     const char *log_file = DEBUG_LOGFILE;
338001ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
338131e31b8aSbellard     struct image_info info1, *info = &info1;
3382edf8e2afSMika Westerberg     struct linux_binprm bprm;
338348e15fc2SNathan Froyd     TaskState *ts;
33849349b4f9SAndreas Färber     CPUArchState *env;
3385586314f2Sbellard     int optind;
338604a6dfebSaurel32     char **target_environ, **wrk;
33877d8cec95Saurel32     char **target_argv;
33887d8cec95Saurel32     int target_argc;
33897d8cec95Saurel32     int i;
3390fd4d81ddSArnaud Patard     int ret;
339131e31b8aSbellard 
3392ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
3393ce008c1fSAndreas Färber 
3394902b3d5cSmalc     qemu_cache_utils_init(envp);
3395902b3d5cSmalc 
339604a6dfebSaurel32     if ((envlist = envlist_create()) == NULL) {
339704a6dfebSaurel32         (void) fprintf(stderr, "Unable to allocate envlist\n");
339804a6dfebSaurel32         exit(1);
339904a6dfebSaurel32     }
340004a6dfebSaurel32 
340104a6dfebSaurel32     /* add current environment into the list */
340204a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
340304a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
340404a6dfebSaurel32     }
340504a6dfebSaurel32 
3406703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
3407703e0e89SRichard Henderson        then we can do little else besides use the default.  */
3408703e0e89SRichard Henderson     {
3409703e0e89SRichard Henderson         struct rlimit lim;
3410703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
341181bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
341281bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur == (target_long)lim.rlim_cur) {
3413703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
3414703e0e89SRichard Henderson         }
3415703e0e89SRichard Henderson     }
3416703e0e89SRichard Henderson 
3417b1f9be31Sj_mayer     cpu_model = NULL;
3418b5ec5ce0Sjohn cooper #if defined(cpudef_setup)
3419b5ec5ce0Sjohn cooper     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
3420b5ec5ce0Sjohn cooper #endif
3421b5ec5ce0Sjohn cooper 
3422c235d738SMatthew Fernandez     /* init debug */
3423c235d738SMatthew Fernandez     cpu_set_log_filename(log_file);
3424fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
34254b5dfd82SPeter Maydell 
342631e31b8aSbellard     /* Zero out regs */
342701ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
342831e31b8aSbellard 
342931e31b8aSbellard     /* Zero out image_info */
343031e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
343131e31b8aSbellard 
3432edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
3433edf8e2afSMika Westerberg 
343474cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
343574cd30b8Sbellard     init_paths(interp_prefix);
343674cd30b8Sbellard 
343746027c07Sbellard     if (cpu_model == NULL) {
3438aaed909aSbellard #if defined(TARGET_I386)
343946027c07Sbellard #ifdef TARGET_X86_64
344046027c07Sbellard         cpu_model = "qemu64";
344146027c07Sbellard #else
344246027c07Sbellard         cpu_model = "qemu32";
344346027c07Sbellard #endif
3444aaed909aSbellard #elif defined(TARGET_ARM)
3445088ab16cSpbrook         cpu_model = "any";
3446d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
3447d2fbca94SGuan Xuetao         cpu_model = "any";
3448aaed909aSbellard #elif defined(TARGET_M68K)
3449aaed909aSbellard         cpu_model = "any";
3450aaed909aSbellard #elif defined(TARGET_SPARC)
3451aaed909aSbellard #ifdef TARGET_SPARC64
3452aaed909aSbellard         cpu_model = "TI UltraSparc II";
3453aaed909aSbellard #else
3454aaed909aSbellard         cpu_model = "Fujitsu MB86904";
345546027c07Sbellard #endif
3456aaed909aSbellard #elif defined(TARGET_MIPS)
3457aaed909aSbellard #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
3458aaed909aSbellard         cpu_model = "20Kc";
3459aaed909aSbellard #else
3460aaed909aSbellard         cpu_model = "24Kf";
3461aaed909aSbellard #endif
3462d962783eSJia Liu #elif defined TARGET_OPENRISC
3463d962783eSJia Liu         cpu_model = "or1200";
3464aaed909aSbellard #elif defined(TARGET_PPC)
34657ded4f52Sbellard #ifdef TARGET_PPC64
3466f7177937SAurelien Jarno         cpu_model = "970fx";
34677ded4f52Sbellard #else
3468aaed909aSbellard         cpu_model = "750";
34697ded4f52Sbellard #endif
3470aaed909aSbellard #else
3471aaed909aSbellard         cpu_model = "any";
3472aaed909aSbellard #endif
3473aaed909aSbellard     }
3474d5ab9713SJan Kiszka     tcg_exec_init(0);
3475d5ab9713SJan Kiszka     cpu_exec_init_all();
347683fb7adfSbellard     /* NOTE: we need to init the CPU at this stage to get
347783fb7adfSbellard        qemu_host_page_size */
3478aaed909aSbellard     env = cpu_init(cpu_model);
3479aaed909aSbellard     if (!env) {
3480aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
3481aaed909aSbellard         exit(1);
3482aaed909aSbellard     }
3483b55a37c9SBlue Swirl #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
3484ff18b762SAndreas Färber     cpu_reset(ENV_GET_CPU(env));
3485b55a37c9SBlue Swirl #endif
3486b55a37c9SBlue Swirl 
3487d5975363Spbrook     thread_env = env;
348854936004Sbellard 
3489b92c47c1Sths     if (getenv("QEMU_STRACE")) {
3490b92c47c1Sths         do_strace = 1;
3491b92c47c1Sths     }
3492b92c47c1Sths 
349304a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
349404a6dfebSaurel32     envlist_free(envlist);
3495b12b6a18Sths 
3496379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
3497379f6698SPaul Brook     /*
3498379f6698SPaul Brook      * Now that page sizes are configured in cpu_init() we can do
3499379f6698SPaul Brook      * proper page alignment for guest_base.
3500379f6698SPaul Brook      */
3501379f6698SPaul Brook     guest_base = HOST_PAGE_ALIGN(guest_base);
350268a1c816SPaul Brook 
350397cc7560SDr. David Alan Gilbert     if (reserved_va || have_guest_base) {
3504806d1021SMeador Inge         guest_base = init_guest_space(guest_base, reserved_va, 0,
3505806d1021SMeador Inge                                       have_guest_base);
3506806d1021SMeador Inge         if (guest_base == (unsigned long)-1) {
3507097b8cb8SPeter Maydell             fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address "
3508097b8cb8SPeter Maydell                     "space for use as guest address space (check your virtual "
3509097b8cb8SPeter Maydell                     "memory ulimit setting or reserve less using -R option)\n",
3510097b8cb8SPeter Maydell                     reserved_va);
351197cc7560SDr. David Alan Gilbert             exit(1);
351297cc7560SDr. David Alan Gilbert         }
3513806d1021SMeador Inge 
3514806d1021SMeador Inge         if (reserved_va) {
3515806d1021SMeador Inge             mmap_next_start = reserved_va;
3516806d1021SMeador Inge         }
351797cc7560SDr. David Alan Gilbert     }
351814f24e14SRichard Henderson #endif /* CONFIG_USE_GUEST_BASE */
3519379f6698SPaul Brook 
3520379f6698SPaul Brook     /*
3521379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
3522379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
352314f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
3524379f6698SPaul Brook      */
352514f24e14SRichard Henderson     {
3526379f6698SPaul Brook         FILE *fp;
3527379f6698SPaul Brook 
3528379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
3529379f6698SPaul Brook             unsigned long tmp;
3530379f6698SPaul Brook             if (fscanf(fp, "%lu", &tmp) == 1) {
3531379f6698SPaul Brook                 mmap_min_addr = tmp;
3532379f6698SPaul Brook                 qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
3533379f6698SPaul Brook             }
3534379f6698SPaul Brook             fclose(fp);
3535379f6698SPaul Brook         }
3536379f6698SPaul Brook     }
3537379f6698SPaul Brook 
35387d8cec95Saurel32     /*
35397d8cec95Saurel32      * Prepare copy of argv vector for target.
35407d8cec95Saurel32      */
35417d8cec95Saurel32     target_argc = argc - optind;
35427d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
35437d8cec95Saurel32     if (target_argv == NULL) {
35447d8cec95Saurel32 	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
35457d8cec95Saurel32 	exit(1);
35467d8cec95Saurel32     }
35477d8cec95Saurel32 
35487d8cec95Saurel32     /*
35497d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
35507d8cec95Saurel32      * argv[0] pointer with the given one.
35517d8cec95Saurel32      */
35527d8cec95Saurel32     i = 0;
35537d8cec95Saurel32     if (argv0 != NULL) {
35547d8cec95Saurel32         target_argv[i++] = strdup(argv0);
35557d8cec95Saurel32     }
35567d8cec95Saurel32     for (; i < target_argc; i++) {
35577d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
35587d8cec95Saurel32     }
35597d8cec95Saurel32     target_argv[target_argc] = NULL;
35607d8cec95Saurel32 
35617267c094SAnthony Liguori     ts = g_malloc0 (sizeof(TaskState));
3562edf8e2afSMika Westerberg     init_task_state(ts);
3563edf8e2afSMika Westerberg     /* build Task State */
3564edf8e2afSMika Westerberg     ts->info = info;
3565edf8e2afSMika Westerberg     ts->bprm = &bprm;
3566edf8e2afSMika Westerberg     env->opaque = ts;
3567edf8e2afSMika Westerberg     task_settid(ts);
3568edf8e2afSMika Westerberg 
3569fd4d81ddSArnaud Patard     ret = loader_exec(filename, target_argv, target_environ, regs,
3570fd4d81ddSArnaud Patard         info, &bprm);
3571fd4d81ddSArnaud Patard     if (ret != 0) {
3572*885c1d10SPeter Maydell         printf("Error while loading %s: %s\n", filename, strerror(-ret));
357374cd30b8Sbellard         _exit(1);
357431e31b8aSbellard     }
357531e31b8aSbellard 
3576b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
3577b12b6a18Sths         free(*wrk);
3578b12b6a18Sths     }
3579b12b6a18Sths 
3580b12b6a18Sths     free(target_environ);
3581b12b6a18Sths 
35822e77eac6Sblueswir1     if (qemu_log_enabled()) {
3583379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
3584379f6698SPaul Brook         qemu_log("guest_base  0x%lx\n", guest_base);
3585379f6698SPaul Brook #endif
358693fcfe39Saliguori         log_page_dump();
358754936004Sbellard 
358893fcfe39Saliguori         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
358993fcfe39Saliguori         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
359093fcfe39Saliguori         qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
35913d177870Sj_mayer                  info->start_code);
359293fcfe39Saliguori         qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
35933d177870Sj_mayer                  info->start_data);
359493fcfe39Saliguori         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
359593fcfe39Saliguori         qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
35963d177870Sj_mayer                  info->start_stack);
359793fcfe39Saliguori         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
359893fcfe39Saliguori         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
35992e77eac6Sblueswir1     }
360031e31b8aSbellard 
360153a5960aSpbrook     target_set_brk(info->brk);
360231e31b8aSbellard     syscall_init();
360366fb9763Sbellard     signal_init();
360431e31b8aSbellard 
36059002ec79SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE)
36069002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
36079002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
36089002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
36099002ec79SRichard Henderson     tcg_prologue_init(&tcg_ctx);
36109002ec79SRichard Henderson #endif
36119002ec79SRichard Henderson 
3612b346ff46Sbellard #if defined(TARGET_I386)
36132e255c6bSbellard     cpu_x86_set_cpl(env, 3);
36142e255c6bSbellard 
36153802ce26Sbellard     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
36161bde465eSbellard     env->hflags |= HF_PE_MASK;
36171bde465eSbellard     if (env->cpuid_features & CPUID_SSE) {
36181bde465eSbellard         env->cr[4] |= CR4_OSFXSR_MASK;
36191bde465eSbellard         env->hflags |= HF_OSFXSR_MASK;
36201bde465eSbellard     }
3621d2fd1af7Sbellard #ifndef TARGET_ABI32
36224dbc422bSbellard     /* enable 64 bit mode if possible */
36234dbc422bSbellard     if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
36244dbc422bSbellard         fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
36254dbc422bSbellard         exit(1);
36264dbc422bSbellard     }
3627d2fd1af7Sbellard     env->cr[4] |= CR4_PAE_MASK;
36284dbc422bSbellard     env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
3629d2fd1af7Sbellard     env->hflags |= HF_LMA_MASK;
3630d2fd1af7Sbellard #endif
36313802ce26Sbellard 
3632415e561fSbellard     /* flags setup : we activate the IRQs by default as in user mode */
3633415e561fSbellard     env->eflags |= IF_MASK;
3634415e561fSbellard 
36356dbad63eSbellard     /* linux register setup */
3636d2fd1af7Sbellard #ifndef TARGET_ABI32
363784409ddbSj_mayer     env->regs[R_EAX] = regs->rax;
363884409ddbSj_mayer     env->regs[R_EBX] = regs->rbx;
363984409ddbSj_mayer     env->regs[R_ECX] = regs->rcx;
364084409ddbSj_mayer     env->regs[R_EDX] = regs->rdx;
364184409ddbSj_mayer     env->regs[R_ESI] = regs->rsi;
364284409ddbSj_mayer     env->regs[R_EDI] = regs->rdi;
364384409ddbSj_mayer     env->regs[R_EBP] = regs->rbp;
364484409ddbSj_mayer     env->regs[R_ESP] = regs->rsp;
364584409ddbSj_mayer     env->eip = regs->rip;
364684409ddbSj_mayer #else
36470ecfa993Sbellard     env->regs[R_EAX] = regs->eax;
36480ecfa993Sbellard     env->regs[R_EBX] = regs->ebx;
36490ecfa993Sbellard     env->regs[R_ECX] = regs->ecx;
36500ecfa993Sbellard     env->regs[R_EDX] = regs->edx;
36510ecfa993Sbellard     env->regs[R_ESI] = regs->esi;
36520ecfa993Sbellard     env->regs[R_EDI] = regs->edi;
36530ecfa993Sbellard     env->regs[R_EBP] = regs->ebp;
36540ecfa993Sbellard     env->regs[R_ESP] = regs->esp;
3655dab2ed99Sbellard     env->eip = regs->eip;
365684409ddbSj_mayer #endif
365731e31b8aSbellard 
3658f4beb510Sbellard     /* linux interrupt setup */
3659e441570fSbalrog #ifndef TARGET_ABI32
3660e441570fSbalrog     env->idt.limit = 511;
3661e441570fSbalrog #else
3662e441570fSbalrog     env->idt.limit = 255;
3663e441570fSbalrog #endif
3664e441570fSbalrog     env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
3665e441570fSbalrog                                 PROT_READ|PROT_WRITE,
3666e441570fSbalrog                                 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3667e441570fSbalrog     idt_table = g2h(env->idt.base);
3668f4beb510Sbellard     set_idt(0, 0);
3669f4beb510Sbellard     set_idt(1, 0);
3670f4beb510Sbellard     set_idt(2, 0);
3671f4beb510Sbellard     set_idt(3, 3);
3672f4beb510Sbellard     set_idt(4, 3);
3673ec95da6cSbellard     set_idt(5, 0);
3674f4beb510Sbellard     set_idt(6, 0);
3675f4beb510Sbellard     set_idt(7, 0);
3676f4beb510Sbellard     set_idt(8, 0);
3677f4beb510Sbellard     set_idt(9, 0);
3678f4beb510Sbellard     set_idt(10, 0);
3679f4beb510Sbellard     set_idt(11, 0);
3680f4beb510Sbellard     set_idt(12, 0);
3681f4beb510Sbellard     set_idt(13, 0);
3682f4beb510Sbellard     set_idt(14, 0);
3683f4beb510Sbellard     set_idt(15, 0);
3684f4beb510Sbellard     set_idt(16, 0);
3685f4beb510Sbellard     set_idt(17, 0);
3686f4beb510Sbellard     set_idt(18, 0);
3687f4beb510Sbellard     set_idt(19, 0);
3688f4beb510Sbellard     set_idt(0x80, 3);
3689f4beb510Sbellard 
36906dbad63eSbellard     /* linux segment setup */
36918d18e893Sbellard     {
36928d18e893Sbellard         uint64_t *gdt_table;
3693e441570fSbalrog         env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
3694e441570fSbalrog                                     PROT_READ|PROT_WRITE,
3695e441570fSbalrog                                     MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
36968d18e893Sbellard         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
3697e441570fSbalrog         gdt_table = g2h(env->gdt.base);
3698d2fd1af7Sbellard #ifdef TARGET_ABI32
3699f4beb510Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
3700f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3701f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
3702d2fd1af7Sbellard #else
3703d2fd1af7Sbellard         /* 64 bit code segment */
3704d2fd1af7Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
3705d2fd1af7Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3706d2fd1af7Sbellard                  DESC_L_MASK |
3707d2fd1af7Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
3708d2fd1af7Sbellard #endif
3709f4beb510Sbellard         write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
3710f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3711f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
37128d18e893Sbellard     }
37136dbad63eSbellard     cpu_x86_load_seg(env, R_CS, __USER_CS);
3714d2fd1af7Sbellard     cpu_x86_load_seg(env, R_SS, __USER_DS);
3715d2fd1af7Sbellard #ifdef TARGET_ABI32
37166dbad63eSbellard     cpu_x86_load_seg(env, R_DS, __USER_DS);
37176dbad63eSbellard     cpu_x86_load_seg(env, R_ES, __USER_DS);
37186dbad63eSbellard     cpu_x86_load_seg(env, R_FS, __USER_DS);
37196dbad63eSbellard     cpu_x86_load_seg(env, R_GS, __USER_DS);
3720d6eb40f6Sths     /* This hack makes Wine work... */
3721d6eb40f6Sths     env->segs[R_FS].selector = 0;
3722d2fd1af7Sbellard #else
3723d2fd1af7Sbellard     cpu_x86_load_seg(env, R_DS, 0);
3724d2fd1af7Sbellard     cpu_x86_load_seg(env, R_ES, 0);
3725d2fd1af7Sbellard     cpu_x86_load_seg(env, R_FS, 0);
3726d2fd1af7Sbellard     cpu_x86_load_seg(env, R_GS, 0);
3727d2fd1af7Sbellard #endif
3728b346ff46Sbellard #elif defined(TARGET_ARM)
3729b346ff46Sbellard     {
3730b346ff46Sbellard         int i;
3731b5ff1b31Sbellard         cpsr_write(env, regs->uregs[16], 0xffffffff);
3732b346ff46Sbellard         for(i = 0; i < 16; i++) {
3733b346ff46Sbellard             env->regs[i] = regs->uregs[i];
3734b346ff46Sbellard         }
3735d8fd2954SPaul Brook         /* Enable BE8.  */
3736d8fd2954SPaul Brook         if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
3737d8fd2954SPaul Brook             && (info->elf_flags & EF_ARM_BE8)) {
3738d8fd2954SPaul Brook             env->bswap_code = 1;
3739d8fd2954SPaul Brook         }
3740b346ff46Sbellard     }
3741d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
3742d2fbca94SGuan Xuetao     {
3743d2fbca94SGuan Xuetao         int i;
3744d2fbca94SGuan Xuetao         cpu_asr_write(env, regs->uregs[32], 0xffffffff);
3745d2fbca94SGuan Xuetao         for (i = 0; i < 32; i++) {
3746d2fbca94SGuan Xuetao             env->regs[i] = regs->uregs[i];
3747d2fbca94SGuan Xuetao         }
3748d2fbca94SGuan Xuetao     }
374993ac68bcSbellard #elif defined(TARGET_SPARC)
3750060366c5Sbellard     {
3751060366c5Sbellard         int i;
3752060366c5Sbellard 	env->pc = regs->pc;
3753060366c5Sbellard 	env->npc = regs->npc;
3754060366c5Sbellard         env->y = regs->y;
3755060366c5Sbellard         for(i = 0; i < 8; i++)
3756060366c5Sbellard             env->gregs[i] = regs->u_regs[i];
3757060366c5Sbellard         for(i = 0; i < 8; i++)
3758060366c5Sbellard             env->regwptr[i] = regs->u_regs[i + 8];
3759060366c5Sbellard     }
376067867308Sbellard #elif defined(TARGET_PPC)
376167867308Sbellard     {
376267867308Sbellard         int i;
37633fc6c082Sbellard 
37640411a972Sj_mayer #if defined(TARGET_PPC64)
37650411a972Sj_mayer #if defined(TARGET_ABI32)
37660411a972Sj_mayer         env->msr &= ~((target_ulong)1 << MSR_SF);
3767e85e7c6eSj_mayer #else
37680411a972Sj_mayer         env->msr |= (target_ulong)1 << MSR_SF;
37690411a972Sj_mayer #endif
377084409ddbSj_mayer #endif
377167867308Sbellard         env->nip = regs->nip;
377267867308Sbellard         for(i = 0; i < 32; i++) {
377367867308Sbellard             env->gpr[i] = regs->gpr[i];
377467867308Sbellard         }
377567867308Sbellard     }
3776e6e5906bSpbrook #elif defined(TARGET_M68K)
3777e6e5906bSpbrook     {
3778e6e5906bSpbrook         env->pc = regs->pc;
3779e6e5906bSpbrook         env->dregs[0] = regs->d0;
3780e6e5906bSpbrook         env->dregs[1] = regs->d1;
3781e6e5906bSpbrook         env->dregs[2] = regs->d2;
3782e6e5906bSpbrook         env->dregs[3] = regs->d3;
3783e6e5906bSpbrook         env->dregs[4] = regs->d4;
3784e6e5906bSpbrook         env->dregs[5] = regs->d5;
3785e6e5906bSpbrook         env->dregs[6] = regs->d6;
3786e6e5906bSpbrook         env->dregs[7] = regs->d7;
3787e6e5906bSpbrook         env->aregs[0] = regs->a0;
3788e6e5906bSpbrook         env->aregs[1] = regs->a1;
3789e6e5906bSpbrook         env->aregs[2] = regs->a2;
3790e6e5906bSpbrook         env->aregs[3] = regs->a3;
3791e6e5906bSpbrook         env->aregs[4] = regs->a4;
3792e6e5906bSpbrook         env->aregs[5] = regs->a5;
3793e6e5906bSpbrook         env->aregs[6] = regs->a6;
3794e6e5906bSpbrook         env->aregs[7] = regs->usp;
3795e6e5906bSpbrook         env->sr = regs->sr;
3796e6e5906bSpbrook         ts->sim_syscalls = 1;
3797e6e5906bSpbrook     }
3798b779e29eSEdgar E. Iglesias #elif defined(TARGET_MICROBLAZE)
3799b779e29eSEdgar E. Iglesias     {
3800b779e29eSEdgar E. Iglesias         env->regs[0] = regs->r0;
3801b779e29eSEdgar E. Iglesias         env->regs[1] = regs->r1;
3802b779e29eSEdgar E. Iglesias         env->regs[2] = regs->r2;
3803b779e29eSEdgar E. Iglesias         env->regs[3] = regs->r3;
3804b779e29eSEdgar E. Iglesias         env->regs[4] = regs->r4;
3805b779e29eSEdgar E. Iglesias         env->regs[5] = regs->r5;
3806b779e29eSEdgar E. Iglesias         env->regs[6] = regs->r6;
3807b779e29eSEdgar E. Iglesias         env->regs[7] = regs->r7;
3808b779e29eSEdgar E. Iglesias         env->regs[8] = regs->r8;
3809b779e29eSEdgar E. Iglesias         env->regs[9] = regs->r9;
3810b779e29eSEdgar E. Iglesias         env->regs[10] = regs->r10;
3811b779e29eSEdgar E. Iglesias         env->regs[11] = regs->r11;
3812b779e29eSEdgar E. Iglesias         env->regs[12] = regs->r12;
3813b779e29eSEdgar E. Iglesias         env->regs[13] = regs->r13;
3814b779e29eSEdgar E. Iglesias         env->regs[14] = regs->r14;
3815b779e29eSEdgar E. Iglesias         env->regs[15] = regs->r15;
3816b779e29eSEdgar E. Iglesias         env->regs[16] = regs->r16;
3817b779e29eSEdgar E. Iglesias         env->regs[17] = regs->r17;
3818b779e29eSEdgar E. Iglesias         env->regs[18] = regs->r18;
3819b779e29eSEdgar E. Iglesias         env->regs[19] = regs->r19;
3820b779e29eSEdgar E. Iglesias         env->regs[20] = regs->r20;
3821b779e29eSEdgar E. Iglesias         env->regs[21] = regs->r21;
3822b779e29eSEdgar E. Iglesias         env->regs[22] = regs->r22;
3823b779e29eSEdgar E. Iglesias         env->regs[23] = regs->r23;
3824b779e29eSEdgar E. Iglesias         env->regs[24] = regs->r24;
3825b779e29eSEdgar E. Iglesias         env->regs[25] = regs->r25;
3826b779e29eSEdgar E. Iglesias         env->regs[26] = regs->r26;
3827b779e29eSEdgar E. Iglesias         env->regs[27] = regs->r27;
3828b779e29eSEdgar E. Iglesias         env->regs[28] = regs->r28;
3829b779e29eSEdgar E. Iglesias         env->regs[29] = regs->r29;
3830b779e29eSEdgar E. Iglesias         env->regs[30] = regs->r30;
3831b779e29eSEdgar E. Iglesias         env->regs[31] = regs->r31;
3832b779e29eSEdgar E. Iglesias         env->sregs[SR_PC] = regs->pc;
3833b779e29eSEdgar E. Iglesias     }
3834048f6b4dSbellard #elif defined(TARGET_MIPS)
3835048f6b4dSbellard     {
3836048f6b4dSbellard         int i;
3837048f6b4dSbellard 
3838048f6b4dSbellard         for(i = 0; i < 32; i++) {
3839b5dc7732Sths             env->active_tc.gpr[i] = regs->regs[i];
3840048f6b4dSbellard         }
38410fddbbf2SNathan Froyd         env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
38420fddbbf2SNathan Froyd         if (regs->cp0_epc & 1) {
38430fddbbf2SNathan Froyd             env->hflags |= MIPS_HFLAG_M16;
38440fddbbf2SNathan Froyd         }
3845048f6b4dSbellard     }
3846d962783eSJia Liu #elif defined(TARGET_OPENRISC)
3847d962783eSJia Liu     {
3848d962783eSJia Liu         int i;
3849d962783eSJia Liu 
3850d962783eSJia Liu         for (i = 0; i < 32; i++) {
3851d962783eSJia Liu             env->gpr[i] = regs->gpr[i];
3852d962783eSJia Liu         }
3853d962783eSJia Liu 
3854d962783eSJia Liu         env->sr = regs->sr;
3855d962783eSJia Liu         env->pc = regs->pc;
3856d962783eSJia Liu     }
3857fdf9b3e8Sbellard #elif defined(TARGET_SH4)
3858fdf9b3e8Sbellard     {
3859fdf9b3e8Sbellard         int i;
3860fdf9b3e8Sbellard 
3861fdf9b3e8Sbellard         for(i = 0; i < 16; i++) {
3862fdf9b3e8Sbellard             env->gregs[i] = regs->regs[i];
3863fdf9b3e8Sbellard         }
3864fdf9b3e8Sbellard         env->pc = regs->pc;
3865fdf9b3e8Sbellard     }
38667a3148a9Sj_mayer #elif defined(TARGET_ALPHA)
38677a3148a9Sj_mayer     {
38687a3148a9Sj_mayer         int i;
38697a3148a9Sj_mayer 
38707a3148a9Sj_mayer         for(i = 0; i < 28; i++) {
3871992f48a0Sblueswir1             env->ir[i] = ((abi_ulong *)regs)[i];
38727a3148a9Sj_mayer         }
3873dad081eeSRichard Henderson         env->ir[IR_SP] = regs->usp;
38747a3148a9Sj_mayer         env->pc = regs->pc;
38757a3148a9Sj_mayer     }
387648733d19Sths #elif defined(TARGET_CRIS)
387748733d19Sths     {
387848733d19Sths 	    env->regs[0] = regs->r0;
387948733d19Sths 	    env->regs[1] = regs->r1;
388048733d19Sths 	    env->regs[2] = regs->r2;
388148733d19Sths 	    env->regs[3] = regs->r3;
388248733d19Sths 	    env->regs[4] = regs->r4;
388348733d19Sths 	    env->regs[5] = regs->r5;
388448733d19Sths 	    env->regs[6] = regs->r6;
388548733d19Sths 	    env->regs[7] = regs->r7;
388648733d19Sths 	    env->regs[8] = regs->r8;
388748733d19Sths 	    env->regs[9] = regs->r9;
388848733d19Sths 	    env->regs[10] = regs->r10;
388948733d19Sths 	    env->regs[11] = regs->r11;
389048733d19Sths 	    env->regs[12] = regs->r12;
389148733d19Sths 	    env->regs[13] = regs->r13;
389248733d19Sths 	    env->regs[14] = info->start_stack;
389348733d19Sths 	    env->regs[15] = regs->acr;
389448733d19Sths 	    env->pc = regs->erp;
389548733d19Sths     }
3896a4c075f1SUlrich Hecht #elif defined(TARGET_S390X)
3897a4c075f1SUlrich Hecht     {
3898a4c075f1SUlrich Hecht             int i;
3899a4c075f1SUlrich Hecht             for (i = 0; i < 16; i++) {
3900a4c075f1SUlrich Hecht                 env->regs[i] = regs->gprs[i];
3901a4c075f1SUlrich Hecht             }
3902a4c075f1SUlrich Hecht             env->psw.mask = regs->psw.mask;
3903a4c075f1SUlrich Hecht             env->psw.addr = regs->psw.addr;
3904a4c075f1SUlrich Hecht     }
3905b346ff46Sbellard #else
3906b346ff46Sbellard #error unsupported target CPU
3907b346ff46Sbellard #endif
390831e31b8aSbellard 
3909d2fbca94SGuan Xuetao #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
3910a87295e8Spbrook     ts->stack_base = info->start_stack;
3911a87295e8Spbrook     ts->heap_base = info->brk;
3912a87295e8Spbrook     /* This will be filled in on the first SYS_HEAPINFO call.  */
3913a87295e8Spbrook     ts->heap_limit = 0;
3914a87295e8Spbrook #endif
3915a87295e8Spbrook 
391674c33bedSbellard     if (gdbstub_port) {
3917ff7a981aSPeter Maydell         if (gdbserver_start(gdbstub_port) < 0) {
3918ff7a981aSPeter Maydell             fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
3919ff7a981aSPeter Maydell                     gdbstub_port);
3920ff7a981aSPeter Maydell             exit(1);
3921ff7a981aSPeter Maydell         }
39221fddef4bSbellard         gdb_handlesig(env, 0);
39231fddef4bSbellard     }
39241b6b029eSbellard     cpu_loop(env);
39251b6b029eSbellard     /* never exits */
392631e31b8aSbellard     return 0;
392731e31b8aSbellard }
3928