xref: /qemu/linux-user/main.c (revision 314992b1)
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"
311de7afc9SPaolo Bonzini #include "qemu/cache-utils.h"
322b41f10eSBlue Swirl #include "cpu.h"
339002ec79SRichard Henderson #include "tcg.h"
341de7afc9SPaolo Bonzini #include "qemu/timer.h"
351de7afc9SPaolo Bonzini #include "qemu/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  */
60*314992b1SAlexander Graf # ifdef TARGET_MIPS
61*314992b1SAlexander Graf /* MIPS only supports 31 bits of virtual address space for user space */
62*314992b1SAlexander Graf unsigned long reserved_va = 0x77000000;
63*314992b1SAlexander Graf # else
64288e65b9SAlexander Graf unsigned long reserved_va = 0xf7000000;
65*314992b1SAlexander Graf # endif
66288e65b9SAlexander Graf #else
6768a1c816SPaul Brook unsigned long reserved_va;
68379f6698SPaul Brook #endif
69288e65b9SAlexander Graf #endif
701b530a6dSaurel32 
71fc9c5412SJohannes Schauer static void usage(void);
72fc9c5412SJohannes Schauer 
737ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
74c5937220Spbrook const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
75586314f2Sbellard 
769de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
779de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
789de5e440Sbellard    by remapping the process stack directly at the right place */
79703e0e89SRichard Henderson unsigned long guest_stack_size = 8 * 1024 * 1024UL;
8031e31b8aSbellard 
8131e31b8aSbellard void gemu_log(const char *fmt, ...)
8231e31b8aSbellard {
8331e31b8aSbellard     va_list ap;
8431e31b8aSbellard 
8531e31b8aSbellard     va_start(ap, fmt);
8631e31b8aSbellard     vfprintf(stderr, fmt, ap);
8731e31b8aSbellard     va_end(ap);
8831e31b8aSbellard }
8931e31b8aSbellard 
908fcd3692Sblueswir1 #if defined(TARGET_I386)
9105390248SAndreas Färber int cpu_get_pic_interrupt(CPUX86State *env)
9292ccca6aSbellard {
9392ccca6aSbellard     return -1;
9492ccca6aSbellard }
958fcd3692Sblueswir1 #endif
9692ccca6aSbellard 
972f7bb878SJuan Quintela #if defined(CONFIG_USE_NPTL)
98d5975363Spbrook /***********************************************************/
99d5975363Spbrook /* Helper routines for implementing atomic operations.  */
100d5975363Spbrook 
101d5975363Spbrook /* To implement exclusive operations we force all cpus to syncronise.
102d5975363Spbrook    We don't require a full sync, only that no cpus are executing guest code.
103d5975363Spbrook    The alternative is to map target atomic ops onto host equivalents,
104d5975363Spbrook    which requires quite a lot of per host/target work.  */
105c2764719Spbrook static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
106d5975363Spbrook static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
107d5975363Spbrook static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
108d5975363Spbrook static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
109d5975363Spbrook static int pending_cpus;
110d5975363Spbrook 
111d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
112d5975363Spbrook void fork_start(void)
113d5975363Spbrook {
114d5975363Spbrook     pthread_mutex_lock(&tb_lock);
115d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
116d032d1b4SRiku Voipio     mmap_fork_start();
117d5975363Spbrook }
118d5975363Spbrook 
119d5975363Spbrook void fork_end(int child)
120d5975363Spbrook {
121d032d1b4SRiku Voipio     mmap_fork_end(child);
122d5975363Spbrook     if (child) {
123d5975363Spbrook         /* Child processes created by fork() only have a single thread.
124d5975363Spbrook            Discard information about the parent threads.  */
125d5975363Spbrook         first_cpu = thread_env;
126d5975363Spbrook         thread_env->next_cpu = NULL;
127d5975363Spbrook         pending_cpus = 0;
128d5975363Spbrook         pthread_mutex_init(&exclusive_lock, NULL);
129c2764719Spbrook         pthread_mutex_init(&cpu_list_mutex, NULL);
130d5975363Spbrook         pthread_cond_init(&exclusive_cond, NULL);
131d5975363Spbrook         pthread_cond_init(&exclusive_resume, NULL);
132d5975363Spbrook         pthread_mutex_init(&tb_lock, NULL);
1332b1319c8Saurel32         gdbserver_fork(thread_env);
134d5975363Spbrook     } else {
135d5975363Spbrook         pthread_mutex_unlock(&exclusive_lock);
136d5975363Spbrook         pthread_mutex_unlock(&tb_lock);
137d5975363Spbrook     }
138d5975363Spbrook }
139d5975363Spbrook 
140d5975363Spbrook /* Wait for pending exclusive operations to complete.  The exclusive lock
141d5975363Spbrook    must be held.  */
142d5975363Spbrook static inline void exclusive_idle(void)
143d5975363Spbrook {
144d5975363Spbrook     while (pending_cpus) {
145d5975363Spbrook         pthread_cond_wait(&exclusive_resume, &exclusive_lock);
146d5975363Spbrook     }
147d5975363Spbrook }
148d5975363Spbrook 
149d5975363Spbrook /* Start an exclusive operation.
150d5975363Spbrook    Must only be called from outside cpu_arm_exec.   */
151d5975363Spbrook static inline void start_exclusive(void)
152d5975363Spbrook {
1539349b4f9SAndreas Färber     CPUArchState *other;
154d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
155d5975363Spbrook     exclusive_idle();
156d5975363Spbrook 
157d5975363Spbrook     pending_cpus = 1;
158d5975363Spbrook     /* Make all other cpus stop executing.  */
159d5975363Spbrook     for (other = first_cpu; other; other = other->next_cpu) {
160d5975363Spbrook         if (other->running) {
161d5975363Spbrook             pending_cpus++;
1623098dba0Saurel32             cpu_exit(other);
163d5975363Spbrook         }
164d5975363Spbrook     }
165d5975363Spbrook     if (pending_cpus > 1) {
166d5975363Spbrook         pthread_cond_wait(&exclusive_cond, &exclusive_lock);
167d5975363Spbrook     }
168d5975363Spbrook }
169d5975363Spbrook 
170d5975363Spbrook /* Finish an exclusive operation.  */
171d5975363Spbrook static inline void end_exclusive(void)
172d5975363Spbrook {
173d5975363Spbrook     pending_cpus = 0;
174d5975363Spbrook     pthread_cond_broadcast(&exclusive_resume);
175d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
176d5975363Spbrook }
177d5975363Spbrook 
178d5975363Spbrook /* Wait for exclusive ops to finish, and begin cpu execution.  */
1799349b4f9SAndreas Färber static inline void cpu_exec_start(CPUArchState *env)
180d5975363Spbrook {
181d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
182d5975363Spbrook     exclusive_idle();
183d5975363Spbrook     env->running = 1;
184d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
185d5975363Spbrook }
186d5975363Spbrook 
187d5975363Spbrook /* Mark cpu as not executing, and release pending exclusive ops.  */
1889349b4f9SAndreas Färber static inline void cpu_exec_end(CPUArchState *env)
189d5975363Spbrook {
190d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
191d5975363Spbrook     env->running = 0;
192d5975363Spbrook     if (pending_cpus > 1) {
193d5975363Spbrook         pending_cpus--;
194d5975363Spbrook         if (pending_cpus == 1) {
195d5975363Spbrook             pthread_cond_signal(&exclusive_cond);
196d5975363Spbrook         }
197d5975363Spbrook     }
198d5975363Spbrook     exclusive_idle();
199d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
200d5975363Spbrook }
201c2764719Spbrook 
202c2764719Spbrook void cpu_list_lock(void)
203c2764719Spbrook {
204c2764719Spbrook     pthread_mutex_lock(&cpu_list_mutex);
205c2764719Spbrook }
206c2764719Spbrook 
207c2764719Spbrook void cpu_list_unlock(void)
208c2764719Spbrook {
209c2764719Spbrook     pthread_mutex_unlock(&cpu_list_mutex);
210c2764719Spbrook }
2112f7bb878SJuan Quintela #else /* if !CONFIG_USE_NPTL */
212d5975363Spbrook /* These are no-ops because we are not threadsafe.  */
2139349b4f9SAndreas Färber static inline void cpu_exec_start(CPUArchState *env)
214d5975363Spbrook {
215d5975363Spbrook }
216d5975363Spbrook 
2179349b4f9SAndreas Färber static inline void cpu_exec_end(CPUArchState *env)
218d5975363Spbrook {
219d5975363Spbrook }
220d5975363Spbrook 
221d5975363Spbrook static inline void start_exclusive(void)
222d5975363Spbrook {
223d5975363Spbrook }
224d5975363Spbrook 
225d5975363Spbrook static inline void end_exclusive(void)
226d5975363Spbrook {
227d5975363Spbrook }
228d5975363Spbrook 
229d5975363Spbrook void fork_start(void)
230d5975363Spbrook {
231d5975363Spbrook }
232d5975363Spbrook 
233d5975363Spbrook void fork_end(int child)
234d5975363Spbrook {
2352b1319c8Saurel32     if (child) {
2362b1319c8Saurel32         gdbserver_fork(thread_env);
2372b1319c8Saurel32     }
238d5975363Spbrook }
239c2764719Spbrook 
240c2764719Spbrook void cpu_list_lock(void)
241c2764719Spbrook {
242c2764719Spbrook }
243c2764719Spbrook 
244c2764719Spbrook void cpu_list_unlock(void)
245c2764719Spbrook {
246c2764719Spbrook }
247d5975363Spbrook #endif
248d5975363Spbrook 
249d5975363Spbrook 
250a541f297Sbellard #ifdef TARGET_I386
251a541f297Sbellard /***********************************************************/
252a541f297Sbellard /* CPUX86 core interface */
253a541f297Sbellard 
25405390248SAndreas Färber void cpu_smm_update(CPUX86State *env)
25502a1602eSbellard {
25602a1602eSbellard }
25702a1602eSbellard 
25828ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env)
25928ab0e2eSbellard {
26028ab0e2eSbellard     return cpu_get_real_ticks();
26128ab0e2eSbellard }
26228ab0e2eSbellard 
263f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
264f4beb510Sbellard                      int flags)
2656dbad63eSbellard {
266f4beb510Sbellard     unsigned int e1, e2;
26753a5960aSpbrook     uint32_t *p;
2686dbad63eSbellard     e1 = (addr << 16) | (limit & 0xffff);
2696dbad63eSbellard     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
270f4beb510Sbellard     e2 |= flags;
27153a5960aSpbrook     p = ptr;
272d538e8f5Smalc     p[0] = tswap32(e1);
273d538e8f5Smalc     p[1] = tswap32(e2);
274f4beb510Sbellard }
275f4beb510Sbellard 
276e441570fSbalrog static uint64_t *idt_table;
277eb38c52cSblueswir1 #ifdef TARGET_X86_64
278d2fd1af7Sbellard static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
279d2fd1af7Sbellard                        uint64_t addr, unsigned int sel)
280d2fd1af7Sbellard {
2814dbc422bSbellard     uint32_t *p, e1, e2;
282d2fd1af7Sbellard     e1 = (addr & 0xffff) | (sel << 16);
283d2fd1af7Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
284d2fd1af7Sbellard     p = ptr;
2854dbc422bSbellard     p[0] = tswap32(e1);
2864dbc422bSbellard     p[1] = tswap32(e2);
2874dbc422bSbellard     p[2] = tswap32(addr >> 32);
2884dbc422bSbellard     p[3] = 0;
289d2fd1af7Sbellard }
290d2fd1af7Sbellard /* only dpl matters as we do only user space emulation */
291d2fd1af7Sbellard static void set_idt(int n, unsigned int dpl)
292d2fd1af7Sbellard {
293d2fd1af7Sbellard     set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
294d2fd1af7Sbellard }
295d2fd1af7Sbellard #else
296f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
297d2fd1af7Sbellard                      uint32_t addr, unsigned int sel)
298f4beb510Sbellard {
2994dbc422bSbellard     uint32_t *p, e1, e2;
300f4beb510Sbellard     e1 = (addr & 0xffff) | (sel << 16);
301f4beb510Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
30253a5960aSpbrook     p = ptr;
3034dbc422bSbellard     p[0] = tswap32(e1);
3044dbc422bSbellard     p[1] = tswap32(e2);
3056dbad63eSbellard }
3066dbad63eSbellard 
307f4beb510Sbellard /* only dpl matters as we do only user space emulation */
308f4beb510Sbellard static void set_idt(int n, unsigned int dpl)
309f4beb510Sbellard {
310f4beb510Sbellard     set_gate(idt_table + n, 0, dpl, 0, 0);
311f4beb510Sbellard }
312d2fd1af7Sbellard #endif
31331e31b8aSbellard 
31489e957e7Sbellard void cpu_loop(CPUX86State *env)
315bc8a22ccSbellard {
316bc8a22ccSbellard     int trapnr;
317992f48a0Sblueswir1     abi_ulong pc;
318c227f099SAnthony Liguori     target_siginfo_t info;
319bc8a22ccSbellard 
320bc8a22ccSbellard     for(;;) {
321bc8a22ccSbellard         trapnr = cpu_x86_exec(env);
322bc8a22ccSbellard         switch(trapnr) {
323f4beb510Sbellard         case 0x80:
324d2fd1af7Sbellard             /* linux syscall from int $0x80 */
3251b6b029eSbellard             env->regs[R_EAX] = do_syscall(env,
3261b6b029eSbellard                                           env->regs[R_EAX],
3271b6b029eSbellard                                           env->regs[R_EBX],
3281b6b029eSbellard                                           env->regs[R_ECX],
3291b6b029eSbellard                                           env->regs[R_EDX],
3301b6b029eSbellard                                           env->regs[R_ESI],
3311b6b029eSbellard                                           env->regs[R_EDI],
3325945cfcbSPeter Maydell                                           env->regs[R_EBP],
3335945cfcbSPeter Maydell                                           0, 0);
334f4beb510Sbellard             break;
335d2fd1af7Sbellard #ifndef TARGET_ABI32
336d2fd1af7Sbellard         case EXCP_SYSCALL:
3375ba18547SStefan Weil             /* linux syscall from syscall instruction */
338d2fd1af7Sbellard             env->regs[R_EAX] = do_syscall(env,
339d2fd1af7Sbellard                                           env->regs[R_EAX],
340d2fd1af7Sbellard                                           env->regs[R_EDI],
341d2fd1af7Sbellard                                           env->regs[R_ESI],
342d2fd1af7Sbellard                                           env->regs[R_EDX],
343d2fd1af7Sbellard                                           env->regs[10],
344d2fd1af7Sbellard                                           env->regs[8],
3455945cfcbSPeter Maydell                                           env->regs[9],
3465945cfcbSPeter Maydell                                           0, 0);
347d2fd1af7Sbellard             env->eip = env->exception_next_eip;
348d2fd1af7Sbellard             break;
349d2fd1af7Sbellard #endif
350f4beb510Sbellard         case EXCP0B_NOSEG:
351f4beb510Sbellard         case EXCP0C_STACK:
352f4beb510Sbellard             info.si_signo = SIGBUS;
353f4beb510Sbellard             info.si_errno = 0;
354f4beb510Sbellard             info.si_code = TARGET_SI_KERNEL;
355f4beb510Sbellard             info._sifields._sigfault._addr = 0;
356624f7979Spbrook             queue_signal(env, info.si_signo, &info);
357f4beb510Sbellard             break;
358f4beb510Sbellard         case EXCP0D_GPF:
359d2fd1af7Sbellard             /* XXX: potential problem if ABI32 */
36084409ddbSj_mayer #ifndef TARGET_X86_64
361f4beb510Sbellard             if (env->eflags & VM_MASK) {
362f4beb510Sbellard                 handle_vm86_fault(env);
36384409ddbSj_mayer             } else
36484409ddbSj_mayer #endif
36584409ddbSj_mayer             {
3669de5e440Sbellard                 info.si_signo = SIGSEGV;
3679de5e440Sbellard                 info.si_errno = 0;
368b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
3699de5e440Sbellard                 info._sifields._sigfault._addr = 0;
370624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
3711b6b029eSbellard             }
3721b6b029eSbellard             break;
373b689bc57Sbellard         case EXCP0E_PAGE:
374b689bc57Sbellard             info.si_signo = SIGSEGV;
375b689bc57Sbellard             info.si_errno = 0;
376b689bc57Sbellard             if (!(env->error_code & 1))
377b689bc57Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
378b689bc57Sbellard             else
379b689bc57Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
380970a87a6Sbellard             info._sifields._sigfault._addr = env->cr[2];
381624f7979Spbrook             queue_signal(env, info.si_signo, &info);
382b689bc57Sbellard             break;
3839de5e440Sbellard         case EXCP00_DIVZ:
38484409ddbSj_mayer #ifndef TARGET_X86_64
385bc8a22ccSbellard             if (env->eflags & VM_MASK) {
386447db213Sbellard                 handle_vm86_trap(env, trapnr);
38784409ddbSj_mayer             } else
38884409ddbSj_mayer #endif
38984409ddbSj_mayer             {
3909de5e440Sbellard                 /* division by zero */
3919de5e440Sbellard                 info.si_signo = SIGFPE;
3929de5e440Sbellard                 info.si_errno = 0;
3939de5e440Sbellard                 info.si_code = TARGET_FPE_INTDIV;
3949de5e440Sbellard                 info._sifields._sigfault._addr = env->eip;
395624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
396bc8a22ccSbellard             }
3979de5e440Sbellard             break;
39801df040bSaliguori         case EXCP01_DB:
399447db213Sbellard         case EXCP03_INT3:
40084409ddbSj_mayer #ifndef TARGET_X86_64
401447db213Sbellard             if (env->eflags & VM_MASK) {
402447db213Sbellard                 handle_vm86_trap(env, trapnr);
40384409ddbSj_mayer             } else
40484409ddbSj_mayer #endif
40584409ddbSj_mayer             {
406447db213Sbellard                 info.si_signo = SIGTRAP;
407447db213Sbellard                 info.si_errno = 0;
40801df040bSaliguori                 if (trapnr == EXCP01_DB) {
409447db213Sbellard                     info.si_code = TARGET_TRAP_BRKPT;
410447db213Sbellard                     info._sifields._sigfault._addr = env->eip;
411447db213Sbellard                 } else {
412447db213Sbellard                     info.si_code = TARGET_SI_KERNEL;
413447db213Sbellard                     info._sifields._sigfault._addr = 0;
414447db213Sbellard                 }
415624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
416447db213Sbellard             }
417447db213Sbellard             break;
4189de5e440Sbellard         case EXCP04_INTO:
4199de5e440Sbellard         case EXCP05_BOUND:
42084409ddbSj_mayer #ifndef TARGET_X86_64
421bc8a22ccSbellard             if (env->eflags & VM_MASK) {
422447db213Sbellard                 handle_vm86_trap(env, trapnr);
42384409ddbSj_mayer             } else
42484409ddbSj_mayer #endif
42584409ddbSj_mayer             {
4269de5e440Sbellard                 info.si_signo = SIGSEGV;
4279de5e440Sbellard                 info.si_errno = 0;
428b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
4299de5e440Sbellard                 info._sifields._sigfault._addr = 0;
430624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
431bc8a22ccSbellard             }
4329de5e440Sbellard             break;
4339de5e440Sbellard         case EXCP06_ILLOP:
4349de5e440Sbellard             info.si_signo = SIGILL;
4359de5e440Sbellard             info.si_errno = 0;
4369de5e440Sbellard             info.si_code = TARGET_ILL_ILLOPN;
4379de5e440Sbellard             info._sifields._sigfault._addr = env->eip;
438624f7979Spbrook             queue_signal(env, info.si_signo, &info);
4399de5e440Sbellard             break;
4409de5e440Sbellard         case EXCP_INTERRUPT:
4419de5e440Sbellard             /* just indicate that signals should be handled asap */
4429de5e440Sbellard             break;
4431fddef4bSbellard         case EXCP_DEBUG:
4441fddef4bSbellard             {
4451fddef4bSbellard                 int sig;
4461fddef4bSbellard 
4471fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
4481fddef4bSbellard                 if (sig)
4491fddef4bSbellard                   {
4501fddef4bSbellard                     info.si_signo = sig;
4511fddef4bSbellard                     info.si_errno = 0;
4521fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
453624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
4541fddef4bSbellard                   }
4551fddef4bSbellard             }
4561fddef4bSbellard             break;
4571b6b029eSbellard         default:
458970a87a6Sbellard             pc = env->segs[R_CS].base + env->eip;
459bc8a22ccSbellard             fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
460bc8a22ccSbellard                     (long)pc, trapnr);
4611b6b029eSbellard             abort();
4621b6b029eSbellard         }
46366fb9763Sbellard         process_pending_signals(env);
4641b6b029eSbellard     }
4651b6b029eSbellard }
466b346ff46Sbellard #endif
467b346ff46Sbellard 
468b346ff46Sbellard #ifdef TARGET_ARM
469b346ff46Sbellard 
470d8fd2954SPaul Brook #define get_user_code_u32(x, gaddr, doswap)             \
471d8fd2954SPaul Brook     ({ abi_long __r = get_user_u32((x), (gaddr));       \
472d8fd2954SPaul Brook         if (!__r && (doswap)) {                         \
473d8fd2954SPaul Brook             (x) = bswap32(x);                           \
474d8fd2954SPaul Brook         }                                               \
475d8fd2954SPaul Brook         __r;                                            \
476d8fd2954SPaul Brook     })
477d8fd2954SPaul Brook 
478d8fd2954SPaul Brook #define get_user_code_u16(x, gaddr, doswap)             \
479d8fd2954SPaul Brook     ({ abi_long __r = get_user_u16((x), (gaddr));       \
480d8fd2954SPaul Brook         if (!__r && (doswap)) {                         \
481d8fd2954SPaul Brook             (x) = bswap16(x);                           \
482d8fd2954SPaul Brook         }                                               \
483d8fd2954SPaul Brook         __r;                                            \
484d8fd2954SPaul Brook     })
485d8fd2954SPaul Brook 
48697cc7560SDr. David Alan Gilbert /*
48797cc7560SDr. David Alan Gilbert  * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
48897cc7560SDr. David Alan Gilbert  * Input:
48997cc7560SDr. David Alan Gilbert  * r0 = pointer to oldval
49097cc7560SDr. David Alan Gilbert  * r1 = pointer to newval
49197cc7560SDr. David Alan Gilbert  * r2 = pointer to target value
49297cc7560SDr. David Alan Gilbert  *
49397cc7560SDr. David Alan Gilbert  * Output:
49497cc7560SDr. David Alan Gilbert  * r0 = 0 if *ptr was changed, non-0 if no exchange happened
49597cc7560SDr. David Alan Gilbert  * C set if *ptr was changed, clear if no exchange happened
49697cc7560SDr. David Alan Gilbert  *
49797cc7560SDr. David Alan Gilbert  * Note segv's in kernel helpers are a bit tricky, we can set the
49897cc7560SDr. David Alan Gilbert  * data address sensibly but the PC address is just the entry point.
49997cc7560SDr. David Alan Gilbert  */
50097cc7560SDr. David Alan Gilbert static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
50197cc7560SDr. David Alan Gilbert {
50297cc7560SDr. David Alan Gilbert     uint64_t oldval, newval, val;
50397cc7560SDr. David Alan Gilbert     uint32_t addr, cpsr;
50497cc7560SDr. David Alan Gilbert     target_siginfo_t info;
50597cc7560SDr. David Alan Gilbert 
50697cc7560SDr. David Alan Gilbert     /* Based on the 32 bit code in do_kernel_trap */
50797cc7560SDr. David Alan Gilbert 
50897cc7560SDr. David Alan Gilbert     /* XXX: This only works between threads, not between processes.
50997cc7560SDr. David Alan Gilbert        It's probably possible to implement this with native host
51097cc7560SDr. David Alan Gilbert        operations. However things like ldrex/strex are much harder so
51197cc7560SDr. David Alan Gilbert        there's not much point trying.  */
51297cc7560SDr. David Alan Gilbert     start_exclusive();
51397cc7560SDr. David Alan Gilbert     cpsr = cpsr_read(env);
51497cc7560SDr. David Alan Gilbert     addr = env->regs[2];
51597cc7560SDr. David Alan Gilbert 
51697cc7560SDr. David Alan Gilbert     if (get_user_u64(oldval, env->regs[0])) {
51797cc7560SDr. David Alan Gilbert         env->cp15.c6_data = env->regs[0];
51897cc7560SDr. David Alan Gilbert         goto segv;
51997cc7560SDr. David Alan Gilbert     };
52097cc7560SDr. David Alan Gilbert 
52197cc7560SDr. David Alan Gilbert     if (get_user_u64(newval, env->regs[1])) {
52297cc7560SDr. David Alan Gilbert         env->cp15.c6_data = env->regs[1];
52397cc7560SDr. David Alan Gilbert         goto segv;
52497cc7560SDr. David Alan Gilbert     };
52597cc7560SDr. David Alan Gilbert 
52697cc7560SDr. David Alan Gilbert     if (get_user_u64(val, addr)) {
52797cc7560SDr. David Alan Gilbert         env->cp15.c6_data = addr;
52897cc7560SDr. David Alan Gilbert         goto segv;
52997cc7560SDr. David Alan Gilbert     }
53097cc7560SDr. David Alan Gilbert 
53197cc7560SDr. David Alan Gilbert     if (val == oldval) {
53297cc7560SDr. David Alan Gilbert         val = newval;
53397cc7560SDr. David Alan Gilbert 
53497cc7560SDr. David Alan Gilbert         if (put_user_u64(val, addr)) {
53597cc7560SDr. David Alan Gilbert             env->cp15.c6_data = addr;
53697cc7560SDr. David Alan Gilbert             goto segv;
53797cc7560SDr. David Alan Gilbert         };
53897cc7560SDr. David Alan Gilbert 
53997cc7560SDr. David Alan Gilbert         env->regs[0] = 0;
54097cc7560SDr. David Alan Gilbert         cpsr |= CPSR_C;
54197cc7560SDr. David Alan Gilbert     } else {
54297cc7560SDr. David Alan Gilbert         env->regs[0] = -1;
54397cc7560SDr. David Alan Gilbert         cpsr &= ~CPSR_C;
54497cc7560SDr. David Alan Gilbert     }
54597cc7560SDr. David Alan Gilbert     cpsr_write(env, cpsr, CPSR_C);
54697cc7560SDr. David Alan Gilbert     end_exclusive();
54797cc7560SDr. David Alan Gilbert     return;
54897cc7560SDr. David Alan Gilbert 
54997cc7560SDr. David Alan Gilbert segv:
55097cc7560SDr. David Alan Gilbert     end_exclusive();
55197cc7560SDr. David Alan Gilbert     /* We get the PC of the entry address - which is as good as anything,
55297cc7560SDr. David Alan Gilbert        on a real kernel what you get depends on which mode it uses. */
55397cc7560SDr. David Alan Gilbert     info.si_signo = SIGSEGV;
55497cc7560SDr. David Alan Gilbert     info.si_errno = 0;
55597cc7560SDr. David Alan Gilbert     /* XXX: check env->error_code */
55697cc7560SDr. David Alan Gilbert     info.si_code = TARGET_SEGV_MAPERR;
55797cc7560SDr. David Alan Gilbert     info._sifields._sigfault._addr = env->cp15.c6_data;
55897cc7560SDr. David Alan Gilbert     queue_signal(env, info.si_signo, &info);
55997cc7560SDr. David Alan Gilbert 
56097cc7560SDr. David Alan Gilbert     end_exclusive();
56197cc7560SDr. David Alan Gilbert }
56297cc7560SDr. David Alan Gilbert 
563fbb4a2e3Spbrook /* Handle a jump to the kernel code page.  */
564fbb4a2e3Spbrook static int
565fbb4a2e3Spbrook do_kernel_trap(CPUARMState *env)
566fbb4a2e3Spbrook {
567fbb4a2e3Spbrook     uint32_t addr;
568fbb4a2e3Spbrook     uint32_t cpsr;
569fbb4a2e3Spbrook     uint32_t val;
570fbb4a2e3Spbrook 
571fbb4a2e3Spbrook     switch (env->regs[15]) {
572fbb4a2e3Spbrook     case 0xffff0fa0: /* __kernel_memory_barrier */
573fbb4a2e3Spbrook         /* ??? No-op. Will need to do better for SMP.  */
574fbb4a2e3Spbrook         break;
575fbb4a2e3Spbrook     case 0xffff0fc0: /* __kernel_cmpxchg */
576d5975363Spbrook          /* XXX: This only works between threads, not between processes.
577d5975363Spbrook             It's probably possible to implement this with native host
578d5975363Spbrook             operations. However things like ldrex/strex are much harder so
579d5975363Spbrook             there's not much point trying.  */
580d5975363Spbrook         start_exclusive();
581fbb4a2e3Spbrook         cpsr = cpsr_read(env);
582fbb4a2e3Spbrook         addr = env->regs[2];
583fbb4a2e3Spbrook         /* FIXME: This should SEGV if the access fails.  */
584fbb4a2e3Spbrook         if (get_user_u32(val, addr))
585fbb4a2e3Spbrook             val = ~env->regs[0];
586fbb4a2e3Spbrook         if (val == env->regs[0]) {
587fbb4a2e3Spbrook             val = env->regs[1];
588fbb4a2e3Spbrook             /* FIXME: Check for segfaults.  */
589fbb4a2e3Spbrook             put_user_u32(val, addr);
590fbb4a2e3Spbrook             env->regs[0] = 0;
591fbb4a2e3Spbrook             cpsr |= CPSR_C;
592fbb4a2e3Spbrook         } else {
593fbb4a2e3Spbrook             env->regs[0] = -1;
594fbb4a2e3Spbrook             cpsr &= ~CPSR_C;
595fbb4a2e3Spbrook         }
596fbb4a2e3Spbrook         cpsr_write(env, cpsr, CPSR_C);
597d5975363Spbrook         end_exclusive();
598fbb4a2e3Spbrook         break;
599fbb4a2e3Spbrook     case 0xffff0fe0: /* __kernel_get_tls */
600fbb4a2e3Spbrook         env->regs[0] = env->cp15.c13_tls2;
601fbb4a2e3Spbrook         break;
60297cc7560SDr. David Alan Gilbert     case 0xffff0f60: /* __kernel_cmpxchg64 */
60397cc7560SDr. David Alan Gilbert         arm_kernel_cmpxchg64_helper(env);
60497cc7560SDr. David Alan Gilbert         break;
60597cc7560SDr. David Alan Gilbert 
606fbb4a2e3Spbrook     default:
607fbb4a2e3Spbrook         return 1;
608fbb4a2e3Spbrook     }
609fbb4a2e3Spbrook     /* Jump back to the caller.  */
610fbb4a2e3Spbrook     addr = env->regs[14];
611fbb4a2e3Spbrook     if (addr & 1) {
612fbb4a2e3Spbrook         env->thumb = 1;
613fbb4a2e3Spbrook         addr &= ~1;
614fbb4a2e3Spbrook     }
615fbb4a2e3Spbrook     env->regs[15] = addr;
616fbb4a2e3Spbrook 
617fbb4a2e3Spbrook     return 0;
618fbb4a2e3Spbrook }
619fbb4a2e3Spbrook 
620426f5abcSPaul Brook static int do_strex(CPUARMState *env)
621426f5abcSPaul Brook {
622426f5abcSPaul Brook     uint32_t val;
623426f5abcSPaul Brook     int size;
624426f5abcSPaul Brook     int rc = 1;
625426f5abcSPaul Brook     int segv = 0;
626426f5abcSPaul Brook     uint32_t addr;
627426f5abcSPaul Brook     start_exclusive();
628426f5abcSPaul Brook     addr = env->exclusive_addr;
629426f5abcSPaul Brook     if (addr != env->exclusive_test) {
630426f5abcSPaul Brook         goto fail;
631426f5abcSPaul Brook     }
632426f5abcSPaul Brook     size = env->exclusive_info & 0xf;
633426f5abcSPaul Brook     switch (size) {
634426f5abcSPaul Brook     case 0:
635426f5abcSPaul Brook         segv = get_user_u8(val, addr);
636426f5abcSPaul Brook         break;
637426f5abcSPaul Brook     case 1:
638426f5abcSPaul Brook         segv = get_user_u16(val, addr);
639426f5abcSPaul Brook         break;
640426f5abcSPaul Brook     case 2:
641426f5abcSPaul Brook     case 3:
642426f5abcSPaul Brook         segv = get_user_u32(val, addr);
643426f5abcSPaul Brook         break;
644f7001a3bSAurelien Jarno     default:
645f7001a3bSAurelien Jarno         abort();
646426f5abcSPaul Brook     }
647426f5abcSPaul Brook     if (segv) {
648426f5abcSPaul Brook         env->cp15.c6_data = addr;
649426f5abcSPaul Brook         goto done;
650426f5abcSPaul Brook     }
651426f5abcSPaul Brook     if (val != env->exclusive_val) {
652426f5abcSPaul Brook         goto fail;
653426f5abcSPaul Brook     }
654426f5abcSPaul Brook     if (size == 3) {
655426f5abcSPaul Brook         segv = get_user_u32(val, addr + 4);
656426f5abcSPaul Brook         if (segv) {
657426f5abcSPaul Brook             env->cp15.c6_data = addr + 4;
658426f5abcSPaul Brook             goto done;
659426f5abcSPaul Brook         }
660426f5abcSPaul Brook         if (val != env->exclusive_high) {
661426f5abcSPaul Brook             goto fail;
662426f5abcSPaul Brook         }
663426f5abcSPaul Brook     }
664426f5abcSPaul Brook     val = env->regs[(env->exclusive_info >> 8) & 0xf];
665426f5abcSPaul Brook     switch (size) {
666426f5abcSPaul Brook     case 0:
667426f5abcSPaul Brook         segv = put_user_u8(val, addr);
668426f5abcSPaul Brook         break;
669426f5abcSPaul Brook     case 1:
670426f5abcSPaul Brook         segv = put_user_u16(val, addr);
671426f5abcSPaul Brook         break;
672426f5abcSPaul Brook     case 2:
673426f5abcSPaul Brook     case 3:
674426f5abcSPaul Brook         segv = put_user_u32(val, addr);
675426f5abcSPaul Brook         break;
676426f5abcSPaul Brook     }
677426f5abcSPaul Brook     if (segv) {
678426f5abcSPaul Brook         env->cp15.c6_data = addr;
679426f5abcSPaul Brook         goto done;
680426f5abcSPaul Brook     }
681426f5abcSPaul Brook     if (size == 3) {
682426f5abcSPaul Brook         val = env->regs[(env->exclusive_info >> 12) & 0xf];
6832c9adbdaSPeter Maydell         segv = put_user_u32(val, addr + 4);
684426f5abcSPaul Brook         if (segv) {
685426f5abcSPaul Brook             env->cp15.c6_data = addr + 4;
686426f5abcSPaul Brook             goto done;
687426f5abcSPaul Brook         }
688426f5abcSPaul Brook     }
689426f5abcSPaul Brook     rc = 0;
690426f5abcSPaul Brook fail:
691725b8a69SPaul Brook     env->regs[15] += 4;
692426f5abcSPaul Brook     env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
693426f5abcSPaul Brook done:
694426f5abcSPaul Brook     end_exclusive();
695426f5abcSPaul Brook     return segv;
696426f5abcSPaul Brook }
697426f5abcSPaul Brook 
698b346ff46Sbellard void cpu_loop(CPUARMState *env)
699b346ff46Sbellard {
700b346ff46Sbellard     int trapnr;
701b346ff46Sbellard     unsigned int n, insn;
702c227f099SAnthony Liguori     target_siginfo_t info;
703b5ff1b31Sbellard     uint32_t addr;
704b346ff46Sbellard 
705b346ff46Sbellard     for(;;) {
706d5975363Spbrook         cpu_exec_start(env);
707b346ff46Sbellard         trapnr = cpu_arm_exec(env);
708d5975363Spbrook         cpu_exec_end(env);
709b346ff46Sbellard         switch(trapnr) {
710b346ff46Sbellard         case EXCP_UDEF:
711c6981055Sbellard             {
712c6981055Sbellard                 TaskState *ts = env->opaque;
713c6981055Sbellard                 uint32_t opcode;
7146d9a42beSaurel32                 int rc;
715c6981055Sbellard 
716c6981055Sbellard                 /* we handle the FPU emulation here, as Linux */
717c6981055Sbellard                 /* we get the opcode */
7182f619698Sbellard                 /* FIXME - what to do if get_user() fails? */
719d8fd2954SPaul Brook                 get_user_code_u32(opcode, env->regs[15], env->bswap_code);
720c6981055Sbellard 
7216d9a42beSaurel32                 rc = EmulateAll(opcode, &ts->fpa, env);
7226d9a42beSaurel32                 if (rc == 0) { /* illegal instruction */
723b346ff46Sbellard                     info.si_signo = SIGILL;
724b346ff46Sbellard                     info.si_errno = 0;
725b346ff46Sbellard                     info.si_code = TARGET_ILL_ILLOPN;
726b346ff46Sbellard                     info._sifields._sigfault._addr = env->regs[15];
727624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
7286d9a42beSaurel32                 } else if (rc < 0) { /* FP exception */
7296d9a42beSaurel32                     int arm_fpe=0;
7306d9a42beSaurel32 
7316d9a42beSaurel32                     /* translate softfloat flags to FPSR flags */
7326d9a42beSaurel32                     if (-rc & float_flag_invalid)
7336d9a42beSaurel32                       arm_fpe |= BIT_IOC;
7346d9a42beSaurel32                     if (-rc & float_flag_divbyzero)
7356d9a42beSaurel32                       arm_fpe |= BIT_DZC;
7366d9a42beSaurel32                     if (-rc & float_flag_overflow)
7376d9a42beSaurel32                       arm_fpe |= BIT_OFC;
7386d9a42beSaurel32                     if (-rc & float_flag_underflow)
7396d9a42beSaurel32                       arm_fpe |= BIT_UFC;
7406d9a42beSaurel32                     if (-rc & float_flag_inexact)
7416d9a42beSaurel32                       arm_fpe |= BIT_IXC;
7426d9a42beSaurel32 
7436d9a42beSaurel32                     FPSR fpsr = ts->fpa.fpsr;
7446d9a42beSaurel32                     //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
7456d9a42beSaurel32 
7466d9a42beSaurel32                     if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
7476d9a42beSaurel32                       info.si_signo = SIGFPE;
7486d9a42beSaurel32                       info.si_errno = 0;
7496d9a42beSaurel32 
7506d9a42beSaurel32                       /* ordered by priority, least first */
7516d9a42beSaurel32                       if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
7526d9a42beSaurel32                       if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
7536d9a42beSaurel32                       if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
7546d9a42beSaurel32                       if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
7556d9a42beSaurel32                       if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
7566d9a42beSaurel32 
7576d9a42beSaurel32                       info._sifields._sigfault._addr = env->regs[15];
758624f7979Spbrook                       queue_signal(env, info.si_signo, &info);
759c6981055Sbellard                     } else {
7606d9a42beSaurel32                       env->regs[15] += 4;
7616d9a42beSaurel32                     }
7626d9a42beSaurel32 
7636d9a42beSaurel32                     /* accumulate unenabled exceptions */
7646d9a42beSaurel32                     if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
7656d9a42beSaurel32                       fpsr |= BIT_IXC;
7666d9a42beSaurel32                     if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
7676d9a42beSaurel32                       fpsr |= BIT_UFC;
7686d9a42beSaurel32                     if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
7696d9a42beSaurel32                       fpsr |= BIT_OFC;
7706d9a42beSaurel32                     if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
7716d9a42beSaurel32                       fpsr |= BIT_DZC;
7726d9a42beSaurel32                     if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
7736d9a42beSaurel32                       fpsr |= BIT_IOC;
7746d9a42beSaurel32                     ts->fpa.fpsr=fpsr;
7756d9a42beSaurel32                 } else { /* everything OK */
776c6981055Sbellard                     /* increment PC */
777c6981055Sbellard                     env->regs[15] += 4;
778c6981055Sbellard                 }
779c6981055Sbellard             }
780b346ff46Sbellard             break;
781b346ff46Sbellard         case EXCP_SWI:
78206c949e6Spbrook         case EXCP_BKPT:
783b346ff46Sbellard             {
784ce4defa0Spbrook                 env->eabi = 1;
785b346ff46Sbellard                 /* system call */
78606c949e6Spbrook                 if (trapnr == EXCP_BKPT) {
78706c949e6Spbrook                     if (env->thumb) {
7882f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
789d8fd2954SPaul Brook                         get_user_code_u16(insn, env->regs[15], env->bswap_code);
79006c949e6Spbrook                         n = insn & 0xff;
79106c949e6Spbrook                         env->regs[15] += 2;
79206c949e6Spbrook                     } else {
7932f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
794d8fd2954SPaul Brook                         get_user_code_u32(insn, env->regs[15], env->bswap_code);
79506c949e6Spbrook                         n = (insn & 0xf) | ((insn >> 4) & 0xff0);
79606c949e6Spbrook                         env->regs[15] += 4;
79706c949e6Spbrook                     }
79806c949e6Spbrook                 } else {
799192c7bd9Sbellard                     if (env->thumb) {
8002f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
801d8fd2954SPaul Brook                         get_user_code_u16(insn, env->regs[15] - 2,
802d8fd2954SPaul Brook                                           env->bswap_code);
803192c7bd9Sbellard                         n = insn & 0xff;
804192c7bd9Sbellard                     } else {
8052f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
806d8fd2954SPaul Brook                         get_user_code_u32(insn, env->regs[15] - 4,
807d8fd2954SPaul Brook                                           env->bswap_code);
808b346ff46Sbellard                         n = insn & 0xffffff;
809192c7bd9Sbellard                     }
81006c949e6Spbrook                 }
811192c7bd9Sbellard 
8126f1f31c0Sbellard                 if (n == ARM_NR_cacheflush) {
813dcfd14b3SBlue Swirl                     /* nop */
814a4f81979Sbellard                 } else if (n == ARM_NR_semihosting
815a4f81979Sbellard                            || n == ARM_NR_thumb_semihosting) {
816a4f81979Sbellard                     env->regs[0] = do_arm_semihosting (env);
8173a1363acSAlexander Graf                 } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
818b346ff46Sbellard                     /* linux syscall */
819ce4defa0Spbrook                     if (env->thumb || n == 0) {
820192c7bd9Sbellard                         n = env->regs[7];
821192c7bd9Sbellard                     } else {
822b346ff46Sbellard                         n -= ARM_SYSCALL_BASE;
823ce4defa0Spbrook                         env->eabi = 0;
824192c7bd9Sbellard                     }
825fbb4a2e3Spbrook                     if ( n > ARM_NR_BASE) {
826fbb4a2e3Spbrook                         switch (n) {
827fbb4a2e3Spbrook                         case ARM_NR_cacheflush:
828dcfd14b3SBlue Swirl                             /* nop */
829fbb4a2e3Spbrook                             break;
830fbb4a2e3Spbrook                         case ARM_NR_set_tls:
831fbb4a2e3Spbrook                             cpu_set_tls(env, env->regs[0]);
832fbb4a2e3Spbrook                             env->regs[0] = 0;
833fbb4a2e3Spbrook                             break;
834fbb4a2e3Spbrook                         default:
835fbb4a2e3Spbrook                             gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
836fbb4a2e3Spbrook                                      n);
837fbb4a2e3Spbrook                             env->regs[0] = -TARGET_ENOSYS;
838fbb4a2e3Spbrook                             break;
839fbb4a2e3Spbrook                         }
840fbb4a2e3Spbrook                     } else {
841b346ff46Sbellard                         env->regs[0] = do_syscall(env,
842b346ff46Sbellard                                                   n,
843b346ff46Sbellard                                                   env->regs[0],
844b346ff46Sbellard                                                   env->regs[1],
845b346ff46Sbellard                                                   env->regs[2],
846b346ff46Sbellard                                                   env->regs[3],
847b346ff46Sbellard                                                   env->regs[4],
8485945cfcbSPeter Maydell                                                   env->regs[5],
8495945cfcbSPeter Maydell                                                   0, 0);
850fbb4a2e3Spbrook                     }
851b346ff46Sbellard                 } else {
852b346ff46Sbellard                     goto error;
853b346ff46Sbellard                 }
854b346ff46Sbellard             }
855b346ff46Sbellard             break;
85643fff238Sbellard         case EXCP_INTERRUPT:
85743fff238Sbellard             /* just indicate that signals should be handled asap */
85843fff238Sbellard             break;
85968016c62Sbellard         case EXCP_PREFETCH_ABORT:
860eae473c1Sbalrog             addr = env->cp15.c6_insn;
861b5ff1b31Sbellard             goto do_segv;
86268016c62Sbellard         case EXCP_DATA_ABORT:
863eae473c1Sbalrog             addr = env->cp15.c6_data;
864b5ff1b31Sbellard         do_segv:
86568016c62Sbellard             {
86668016c62Sbellard                 info.si_signo = SIGSEGV;
86768016c62Sbellard                 info.si_errno = 0;
86868016c62Sbellard                 /* XXX: check env->error_code */
86968016c62Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
870b5ff1b31Sbellard                 info._sifields._sigfault._addr = addr;
871624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
87268016c62Sbellard             }
87368016c62Sbellard             break;
8741fddef4bSbellard         case EXCP_DEBUG:
8751fddef4bSbellard             {
8761fddef4bSbellard                 int sig;
8771fddef4bSbellard 
8781fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
8791fddef4bSbellard                 if (sig)
8801fddef4bSbellard                   {
8811fddef4bSbellard                     info.si_signo = sig;
8821fddef4bSbellard                     info.si_errno = 0;
8831fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
884624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
8851fddef4bSbellard                   }
8861fddef4bSbellard             }
8871fddef4bSbellard             break;
888fbb4a2e3Spbrook         case EXCP_KERNEL_TRAP:
889fbb4a2e3Spbrook             if (do_kernel_trap(env))
890fbb4a2e3Spbrook               goto error;
891fbb4a2e3Spbrook             break;
892426f5abcSPaul Brook         case EXCP_STREX:
893426f5abcSPaul Brook             if (do_strex(env)) {
894426f5abcSPaul Brook                 addr = env->cp15.c6_data;
895426f5abcSPaul Brook                 goto do_segv;
896426f5abcSPaul Brook             }
897e9273455SPaul Brook             break;
898b346ff46Sbellard         default:
899b346ff46Sbellard         error:
900b346ff46Sbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
901b346ff46Sbellard                     trapnr);
9027fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
903b346ff46Sbellard             abort();
904b346ff46Sbellard         }
905b346ff46Sbellard         process_pending_signals(env);
906b346ff46Sbellard     }
907b346ff46Sbellard }
908b346ff46Sbellard 
909b346ff46Sbellard #endif
9101b6b029eSbellard 
911d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32
912d2fbca94SGuan Xuetao 
91305390248SAndreas Färber void cpu_loop(CPUUniCore32State *env)
914d2fbca94SGuan Xuetao {
915d2fbca94SGuan Xuetao     int trapnr;
916d2fbca94SGuan Xuetao     unsigned int n, insn;
917d2fbca94SGuan Xuetao     target_siginfo_t info;
918d2fbca94SGuan Xuetao 
919d2fbca94SGuan Xuetao     for (;;) {
920d2fbca94SGuan Xuetao         cpu_exec_start(env);
921d2fbca94SGuan Xuetao         trapnr = uc32_cpu_exec(env);
922d2fbca94SGuan Xuetao         cpu_exec_end(env);
923d2fbca94SGuan Xuetao         switch (trapnr) {
924d2fbca94SGuan Xuetao         case UC32_EXCP_PRIV:
925d2fbca94SGuan Xuetao             {
926d2fbca94SGuan Xuetao                 /* system call */
927d2fbca94SGuan Xuetao                 get_user_u32(insn, env->regs[31] - 4);
928d2fbca94SGuan Xuetao                 n = insn & 0xffffff;
929d2fbca94SGuan Xuetao 
930d2fbca94SGuan Xuetao                 if (n >= UC32_SYSCALL_BASE) {
931d2fbca94SGuan Xuetao                     /* linux syscall */
932d2fbca94SGuan Xuetao                     n -= UC32_SYSCALL_BASE;
933d2fbca94SGuan Xuetao                     if (n == UC32_SYSCALL_NR_set_tls) {
934d2fbca94SGuan Xuetao                             cpu_set_tls(env, env->regs[0]);
935d2fbca94SGuan Xuetao                             env->regs[0] = 0;
936d2fbca94SGuan Xuetao                     } else {
937d2fbca94SGuan Xuetao                         env->regs[0] = do_syscall(env,
938d2fbca94SGuan Xuetao                                                   n,
939d2fbca94SGuan Xuetao                                                   env->regs[0],
940d2fbca94SGuan Xuetao                                                   env->regs[1],
941d2fbca94SGuan Xuetao                                                   env->regs[2],
942d2fbca94SGuan Xuetao                                                   env->regs[3],
943d2fbca94SGuan Xuetao                                                   env->regs[4],
9445945cfcbSPeter Maydell                                                   env->regs[5],
9455945cfcbSPeter Maydell                                                   0, 0);
946d2fbca94SGuan Xuetao                     }
947d2fbca94SGuan Xuetao                 } else {
948d2fbca94SGuan Xuetao                     goto error;
949d2fbca94SGuan Xuetao                 }
950d2fbca94SGuan Xuetao             }
951d2fbca94SGuan Xuetao             break;
952d48813ddSGuan Xuetao         case UC32_EXCP_DTRAP:
953d48813ddSGuan Xuetao         case UC32_EXCP_ITRAP:
954d2fbca94SGuan Xuetao             info.si_signo = SIGSEGV;
955d2fbca94SGuan Xuetao             info.si_errno = 0;
956d2fbca94SGuan Xuetao             /* XXX: check env->error_code */
957d2fbca94SGuan Xuetao             info.si_code = TARGET_SEGV_MAPERR;
958d2fbca94SGuan Xuetao             info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
959d2fbca94SGuan Xuetao             queue_signal(env, info.si_signo, &info);
960d2fbca94SGuan Xuetao             break;
961d2fbca94SGuan Xuetao         case EXCP_INTERRUPT:
962d2fbca94SGuan Xuetao             /* just indicate that signals should be handled asap */
963d2fbca94SGuan Xuetao             break;
964d2fbca94SGuan Xuetao         case EXCP_DEBUG:
965d2fbca94SGuan Xuetao             {
966d2fbca94SGuan Xuetao                 int sig;
967d2fbca94SGuan Xuetao 
968d2fbca94SGuan Xuetao                 sig = gdb_handlesig(env, TARGET_SIGTRAP);
969d2fbca94SGuan Xuetao                 if (sig) {
970d2fbca94SGuan Xuetao                     info.si_signo = sig;
971d2fbca94SGuan Xuetao                     info.si_errno = 0;
972d2fbca94SGuan Xuetao                     info.si_code = TARGET_TRAP_BRKPT;
973d2fbca94SGuan Xuetao                     queue_signal(env, info.si_signo, &info);
974d2fbca94SGuan Xuetao                 }
975d2fbca94SGuan Xuetao             }
976d2fbca94SGuan Xuetao             break;
977d2fbca94SGuan Xuetao         default:
978d2fbca94SGuan Xuetao             goto error;
979d2fbca94SGuan Xuetao         }
980d2fbca94SGuan Xuetao         process_pending_signals(env);
981d2fbca94SGuan Xuetao     }
982d2fbca94SGuan Xuetao 
983d2fbca94SGuan Xuetao error:
984d2fbca94SGuan Xuetao     fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
985d2fbca94SGuan Xuetao     cpu_dump_state(env, stderr, fprintf, 0);
986d2fbca94SGuan Xuetao     abort();
987d2fbca94SGuan Xuetao }
988d2fbca94SGuan Xuetao #endif
989d2fbca94SGuan Xuetao 
99093ac68bcSbellard #ifdef TARGET_SPARC
991ed23fbd9Sblueswir1 #define SPARC64_STACK_BIAS 2047
99293ac68bcSbellard 
993060366c5Sbellard //#define DEBUG_WIN
994060366c5Sbellard 
9952623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info
9962623cbafSbellard    can be found at http://www.sics.se/~psm/sparcstack.html */
997060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
998060366c5Sbellard {
9991a14026eSblueswir1     index = (index + cwp * 16) % (16 * env->nwindows);
1000060366c5Sbellard     /* wrap handling : if cwp is on the last window, then we use the
1001060366c5Sbellard        registers 'after' the end */
10021a14026eSblueswir1     if (index < 8 && env->cwp == env->nwindows - 1)
10031a14026eSblueswir1         index += 16 * env->nwindows;
1004060366c5Sbellard     return index;
1005060366c5Sbellard }
1006060366c5Sbellard 
10072623cbafSbellard /* save the register window 'cwp1' */
10082623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1)
1009060366c5Sbellard {
10102623cbafSbellard     unsigned int i;
1011992f48a0Sblueswir1     abi_ulong sp_ptr;
1012060366c5Sbellard 
101353a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1014ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1015ed23fbd9Sblueswir1     if (sp_ptr & 3)
1016ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1017ed23fbd9Sblueswir1 #endif
1018060366c5Sbellard #if defined(DEBUG_WIN)
10192daf0284Sblueswir1     printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
10202daf0284Sblueswir1            sp_ptr, cwp1);
1021060366c5Sbellard #endif
10222623cbafSbellard     for(i = 0; i < 16; i++) {
10232f619698Sbellard         /* FIXME - what to do if put_user() fails? */
10242f619698Sbellard         put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1025992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
10262623cbafSbellard     }
1027060366c5Sbellard }
1028060366c5Sbellard 
1029060366c5Sbellard static void save_window(CPUSPARCState *env)
1030060366c5Sbellard {
10315ef54116Sbellard #ifndef TARGET_SPARC64
10322623cbafSbellard     unsigned int new_wim;
10331a14026eSblueswir1     new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
10341a14026eSblueswir1         ((1LL << env->nwindows) - 1);
10351a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10362623cbafSbellard     env->wim = new_wim;
10375ef54116Sbellard #else
10381a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10395ef54116Sbellard     env->cansave++;
10405ef54116Sbellard     env->canrestore--;
10415ef54116Sbellard #endif
1042060366c5Sbellard }
1043060366c5Sbellard 
1044060366c5Sbellard static void restore_window(CPUSPARCState *env)
1045060366c5Sbellard {
1046eda52953Sblueswir1 #ifndef TARGET_SPARC64
1047eda52953Sblueswir1     unsigned int new_wim;
1048eda52953Sblueswir1 #endif
1049eda52953Sblueswir1     unsigned int i, cwp1;
1050992f48a0Sblueswir1     abi_ulong sp_ptr;
1051060366c5Sbellard 
1052eda52953Sblueswir1 #ifndef TARGET_SPARC64
10531a14026eSblueswir1     new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
10541a14026eSblueswir1         ((1LL << env->nwindows) - 1);
1055eda52953Sblueswir1 #endif
1056060366c5Sbellard 
1057060366c5Sbellard     /* restore the invalid window */
10581a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
105953a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1060ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1061ed23fbd9Sblueswir1     if (sp_ptr & 3)
1062ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1063ed23fbd9Sblueswir1 #endif
1064060366c5Sbellard #if defined(DEBUG_WIN)
10652daf0284Sblueswir1     printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
10662daf0284Sblueswir1            sp_ptr, cwp1);
1067060366c5Sbellard #endif
10682623cbafSbellard     for(i = 0; i < 16; i++) {
10692f619698Sbellard         /* FIXME - what to do if get_user() fails? */
10702f619698Sbellard         get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1071992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
10722623cbafSbellard     }
10735ef54116Sbellard #ifdef TARGET_SPARC64
10745ef54116Sbellard     env->canrestore++;
10751a14026eSblueswir1     if (env->cleanwin < env->nwindows - 1)
10765ef54116Sbellard         env->cleanwin++;
10775ef54116Sbellard     env->cansave--;
1078eda52953Sblueswir1 #else
1079eda52953Sblueswir1     env->wim = new_wim;
10805ef54116Sbellard #endif
1081060366c5Sbellard }
1082060366c5Sbellard 
1083060366c5Sbellard static void flush_windows(CPUSPARCState *env)
1084060366c5Sbellard {
1085060366c5Sbellard     int offset, cwp1;
10862623cbafSbellard 
10872623cbafSbellard     offset = 1;
1088060366c5Sbellard     for(;;) {
1089060366c5Sbellard         /* if restore would invoke restore_window(), then we can stop */
10901a14026eSblueswir1         cwp1 = cpu_cwp_inc(env, env->cwp + offset);
1091eda52953Sblueswir1 #ifndef TARGET_SPARC64
1092060366c5Sbellard         if (env->wim & (1 << cwp1))
1093060366c5Sbellard             break;
1094eda52953Sblueswir1 #else
1095eda52953Sblueswir1         if (env->canrestore == 0)
1096eda52953Sblueswir1             break;
1097eda52953Sblueswir1         env->cansave++;
1098eda52953Sblueswir1         env->canrestore--;
1099eda52953Sblueswir1 #endif
11002623cbafSbellard         save_window_offset(env, cwp1);
1101060366c5Sbellard         offset++;
1102060366c5Sbellard     }
11031a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
1104eda52953Sblueswir1 #ifndef TARGET_SPARC64
1105eda52953Sblueswir1     /* set wim so that restore will reload the registers */
11062623cbafSbellard     env->wim = 1 << cwp1;
1107eda52953Sblueswir1 #endif
11082623cbafSbellard #if defined(DEBUG_WIN)
11092623cbafSbellard     printf("flush_windows: nb=%d\n", offset - 1);
111080a9d035Sbellard #endif
11112623cbafSbellard }
1112060366c5Sbellard 
111393ac68bcSbellard void cpu_loop (CPUSPARCState *env)
111493ac68bcSbellard {
11152cc20260SRichard Henderson     int trapnr;
11162cc20260SRichard Henderson     abi_long ret;
1117c227f099SAnthony Liguori     target_siginfo_t info;
111893ac68bcSbellard 
111993ac68bcSbellard     while (1) {
112093ac68bcSbellard         trapnr = cpu_sparc_exec (env);
112193ac68bcSbellard 
112220132b96SRichard Henderson         /* Compute PSR before exposing state.  */
112320132b96SRichard Henderson         if (env->cc_op != CC_OP_FLAGS) {
112420132b96SRichard Henderson             cpu_get_psr(env);
112520132b96SRichard Henderson         }
112620132b96SRichard Henderson 
112793ac68bcSbellard         switch (trapnr) {
11285ef54116Sbellard #ifndef TARGET_SPARC64
1129060366c5Sbellard         case 0x88:
1130060366c5Sbellard         case 0x90:
11315ef54116Sbellard #else
1132cb33da57Sblueswir1         case 0x110:
11335ef54116Sbellard         case 0x16d:
11345ef54116Sbellard #endif
1135060366c5Sbellard             ret = do_syscall (env, env->gregs[1],
1136060366c5Sbellard                               env->regwptr[0], env->regwptr[1],
1137060366c5Sbellard                               env->regwptr[2], env->regwptr[3],
11385945cfcbSPeter Maydell                               env->regwptr[4], env->regwptr[5],
11395945cfcbSPeter Maydell                               0, 0);
11402cc20260SRichard Henderson             if ((abi_ulong)ret >= (abi_ulong)(-515)) {
1141992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
114227908725Sbellard                 env->xcc |= PSR_CARRY;
114327908725Sbellard #else
114493ac68bcSbellard                 env->psr |= PSR_CARRY;
114527908725Sbellard #endif
1146060366c5Sbellard                 ret = -ret;
1147060366c5Sbellard             } else {
1148992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
114927908725Sbellard                 env->xcc &= ~PSR_CARRY;
115027908725Sbellard #else
1151060366c5Sbellard                 env->psr &= ~PSR_CARRY;
115227908725Sbellard #endif
1153060366c5Sbellard             }
1154060366c5Sbellard             env->regwptr[0] = ret;
1155060366c5Sbellard             /* next instruction */
1156060366c5Sbellard             env->pc = env->npc;
1157060366c5Sbellard             env->npc = env->npc + 4;
1158060366c5Sbellard             break;
1159060366c5Sbellard         case 0x83: /* flush windows */
1160992f48a0Sblueswir1 #ifdef TARGET_ABI32
1161992f48a0Sblueswir1         case 0x103:
1162992f48a0Sblueswir1 #endif
11632623cbafSbellard             flush_windows(env);
1164060366c5Sbellard             /* next instruction */
1165060366c5Sbellard             env->pc = env->npc;
1166060366c5Sbellard             env->npc = env->npc + 4;
1167060366c5Sbellard             break;
11683475187dSbellard #ifndef TARGET_SPARC64
1169060366c5Sbellard         case TT_WIN_OVF: /* window overflow */
1170060366c5Sbellard             save_window(env);
1171060366c5Sbellard             break;
1172060366c5Sbellard         case TT_WIN_UNF: /* window underflow */
1173060366c5Sbellard             restore_window(env);
117493ac68bcSbellard             break;
117561ff6f58Sbellard         case TT_TFAULT:
117661ff6f58Sbellard         case TT_DFAULT:
117761ff6f58Sbellard             {
117859f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
117961ff6f58Sbellard                 info.si_errno = 0;
118061ff6f58Sbellard                 /* XXX: check env->error_code */
118161ff6f58Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
118261ff6f58Sbellard                 info._sifields._sigfault._addr = env->mmuregs[4];
1183624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
118461ff6f58Sbellard             }
118561ff6f58Sbellard             break;
11863475187dSbellard #else
11875ef54116Sbellard         case TT_SPILL: /* window overflow */
11885ef54116Sbellard             save_window(env);
11895ef54116Sbellard             break;
11905ef54116Sbellard         case TT_FILL: /* window underflow */
11915ef54116Sbellard             restore_window(env);
11925ef54116Sbellard             break;
11937f84a729Sblueswir1         case TT_TFAULT:
11947f84a729Sblueswir1         case TT_DFAULT:
11957f84a729Sblueswir1             {
119659f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
11977f84a729Sblueswir1                 info.si_errno = 0;
11987f84a729Sblueswir1                 /* XXX: check env->error_code */
11997f84a729Sblueswir1                 info.si_code = TARGET_SEGV_MAPERR;
12007f84a729Sblueswir1                 if (trapnr == TT_DFAULT)
12017f84a729Sblueswir1                     info._sifields._sigfault._addr = env->dmmuregs[4];
12027f84a729Sblueswir1                 else
12038194f35aSIgor Kovalenko                     info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
1204624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
12057f84a729Sblueswir1             }
12067f84a729Sblueswir1             break;
120727524dc3Sbellard #ifndef TARGET_ABI32
12085bfb56b2Sblueswir1         case 0x16e:
12095bfb56b2Sblueswir1             flush_windows(env);
12105bfb56b2Sblueswir1             sparc64_get_context(env);
12115bfb56b2Sblueswir1             break;
12125bfb56b2Sblueswir1         case 0x16f:
12135bfb56b2Sblueswir1             flush_windows(env);
12145bfb56b2Sblueswir1             sparc64_set_context(env);
12155bfb56b2Sblueswir1             break;
12163475187dSbellard #endif
121727524dc3Sbellard #endif
121848dc41ebSbellard         case EXCP_INTERRUPT:
121948dc41ebSbellard             /* just indicate that signals should be handled asap */
1220e80cfcfcSbellard             break;
122175f22e4eSRichard Henderson         case TT_ILL_INSN:
122275f22e4eSRichard Henderson             {
122375f22e4eSRichard Henderson                 info.si_signo = TARGET_SIGILL;
122475f22e4eSRichard Henderson                 info.si_errno = 0;
122575f22e4eSRichard Henderson                 info.si_code = TARGET_ILL_ILLOPC;
122675f22e4eSRichard Henderson                 info._sifields._sigfault._addr = env->pc;
122775f22e4eSRichard Henderson                 queue_signal(env, info.si_signo, &info);
122875f22e4eSRichard Henderson             }
122975f22e4eSRichard Henderson             break;
12301fddef4bSbellard         case EXCP_DEBUG:
12311fddef4bSbellard             {
12321fddef4bSbellard                 int sig;
12331fddef4bSbellard 
12341fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
12351fddef4bSbellard                 if (sig)
12361fddef4bSbellard                   {
12371fddef4bSbellard                     info.si_signo = sig;
12381fddef4bSbellard                     info.si_errno = 0;
12391fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
1240624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
12411fddef4bSbellard                   }
12421fddef4bSbellard             }
12431fddef4bSbellard             break;
124493ac68bcSbellard         default:
1245060366c5Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
12467fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
124793ac68bcSbellard             exit (1);
124893ac68bcSbellard         }
124993ac68bcSbellard         process_pending_signals (env);
125093ac68bcSbellard     }
125193ac68bcSbellard }
125293ac68bcSbellard 
125393ac68bcSbellard #endif
125493ac68bcSbellard 
125567867308Sbellard #ifdef TARGET_PPC
125605390248SAndreas Färber static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
12579fddaa0cSbellard {
12589fddaa0cSbellard     /* TO FIX */
12599fddaa0cSbellard     return 0;
12609fddaa0cSbellard }
12619fddaa0cSbellard 
126205390248SAndreas Färber uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
12639fddaa0cSbellard {
1264e3ea6529SAlexander Graf     return cpu_ppc_get_tb(env);
12659fddaa0cSbellard }
12669fddaa0cSbellard 
126705390248SAndreas Färber uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
12689fddaa0cSbellard {
12699fddaa0cSbellard     return cpu_ppc_get_tb(env) >> 32;
12709fddaa0cSbellard }
12719fddaa0cSbellard 
127205390248SAndreas Färber uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
12739fddaa0cSbellard {
1274b711de95SAurelien Jarno     return cpu_ppc_get_tb(env);
12759fddaa0cSbellard }
12769fddaa0cSbellard 
127705390248SAndreas Färber uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
12789fddaa0cSbellard {
1279a062e36cSj_mayer     return cpu_ppc_get_tb(env) >> 32;
12809fddaa0cSbellard }
12819fddaa0cSbellard 
128205390248SAndreas Färber uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
128376a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_load_tbu") ));
128476a66253Sj_mayer 
128505390248SAndreas Färber uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
12869fddaa0cSbellard {
128776a66253Sj_mayer     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
12889fddaa0cSbellard }
12899fddaa0cSbellard 
1290a750fc0bSj_mayer /* XXX: to be fixed */
129173b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
1292a750fc0bSj_mayer {
1293a750fc0bSj_mayer     return -1;
1294a750fc0bSj_mayer }
1295a750fc0bSj_mayer 
129673b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
1297a750fc0bSj_mayer {
1298a750fc0bSj_mayer     return -1;
1299a750fc0bSj_mayer }
1300a750fc0bSj_mayer 
1301001faf32SBlue Swirl #define EXCP_DUMP(env, fmt, ...)                                        \
1302e1833e1fSj_mayer do {                                                                    \
1303001faf32SBlue Swirl     fprintf(stderr, fmt , ## __VA_ARGS__);                              \
1304e1833e1fSj_mayer     cpu_dump_state(env, stderr, fprintf, 0);                            \
1305001faf32SBlue Swirl     qemu_log(fmt, ## __VA_ARGS__);                                      \
1306eeacee4dSBlue Swirl     if (qemu_log_enabled()) {                                           \
130793fcfe39Saliguori         log_cpu_state(env, 0);                                          \
1308eeacee4dSBlue Swirl     }                                                                   \
1309e1833e1fSj_mayer } while (0)
1310e1833e1fSj_mayer 
131156f066bbSNathan Froyd static int do_store_exclusive(CPUPPCState *env)
131256f066bbSNathan Froyd {
131356f066bbSNathan Froyd     target_ulong addr;
131456f066bbSNathan Froyd     target_ulong page_addr;
131556f066bbSNathan Froyd     target_ulong val;
131656f066bbSNathan Froyd     int flags;
131756f066bbSNathan Froyd     int segv = 0;
131856f066bbSNathan Froyd 
131956f066bbSNathan Froyd     addr = env->reserve_ea;
132056f066bbSNathan Froyd     page_addr = addr & TARGET_PAGE_MASK;
132156f066bbSNathan Froyd     start_exclusive();
132256f066bbSNathan Froyd     mmap_lock();
132356f066bbSNathan Froyd     flags = page_get_flags(page_addr);
132456f066bbSNathan Froyd     if ((flags & PAGE_READ) == 0) {
132556f066bbSNathan Froyd         segv = 1;
132656f066bbSNathan Froyd     } else {
132756f066bbSNathan Froyd         int reg = env->reserve_info & 0x1f;
132856f066bbSNathan Froyd         int size = (env->reserve_info >> 5) & 0xf;
132956f066bbSNathan Froyd         int stored = 0;
133056f066bbSNathan Froyd 
133156f066bbSNathan Froyd         if (addr == env->reserve_addr) {
133256f066bbSNathan Froyd             switch (size) {
133356f066bbSNathan Froyd             case 1: segv = get_user_u8(val, addr); break;
133456f066bbSNathan Froyd             case 2: segv = get_user_u16(val, addr); break;
133556f066bbSNathan Froyd             case 4: segv = get_user_u32(val, addr); break;
133656f066bbSNathan Froyd #if defined(TARGET_PPC64)
133756f066bbSNathan Froyd             case 8: segv = get_user_u64(val, addr); break;
133856f066bbSNathan Froyd #endif
133956f066bbSNathan Froyd             default: abort();
134056f066bbSNathan Froyd             }
134156f066bbSNathan Froyd             if (!segv && val == env->reserve_val) {
134256f066bbSNathan Froyd                 val = env->gpr[reg];
134356f066bbSNathan Froyd                 switch (size) {
134456f066bbSNathan Froyd                 case 1: segv = put_user_u8(val, addr); break;
134556f066bbSNathan Froyd                 case 2: segv = put_user_u16(val, addr); break;
134656f066bbSNathan Froyd                 case 4: segv = put_user_u32(val, addr); break;
134756f066bbSNathan Froyd #if defined(TARGET_PPC64)
134856f066bbSNathan Froyd                 case 8: segv = put_user_u64(val, addr); break;
134956f066bbSNathan Froyd #endif
135056f066bbSNathan Froyd                 default: abort();
135156f066bbSNathan Froyd                 }
135256f066bbSNathan Froyd                 if (!segv) {
135356f066bbSNathan Froyd                     stored = 1;
135456f066bbSNathan Froyd                 }
135556f066bbSNathan Froyd             }
135656f066bbSNathan Froyd         }
135756f066bbSNathan Froyd         env->crf[0] = (stored << 1) | xer_so;
135856f066bbSNathan Froyd         env->reserve_addr = (target_ulong)-1;
135956f066bbSNathan Froyd     }
136056f066bbSNathan Froyd     if (!segv) {
136156f066bbSNathan Froyd         env->nip += 4;
136256f066bbSNathan Froyd     }
136356f066bbSNathan Froyd     mmap_unlock();
136456f066bbSNathan Froyd     end_exclusive();
136556f066bbSNathan Froyd     return segv;
136656f066bbSNathan Froyd }
136756f066bbSNathan Froyd 
136867867308Sbellard void cpu_loop(CPUPPCState *env)
136967867308Sbellard {
1370c227f099SAnthony Liguori     target_siginfo_t info;
137161190b14Sbellard     int trapnr;
13729e0e2f96SRichard Henderson     target_ulong ret;
137367867308Sbellard 
137467867308Sbellard     for(;;) {
137556f066bbSNathan Froyd         cpu_exec_start(env);
137667867308Sbellard         trapnr = cpu_ppc_exec(env);
137756f066bbSNathan Froyd         cpu_exec_end(env);
137867867308Sbellard         switch(trapnr) {
1379e1833e1fSj_mayer         case POWERPC_EXCP_NONE:
1380e1833e1fSj_mayer             /* Just go on */
138167867308Sbellard             break;
1382e1833e1fSj_mayer         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
1383e1833e1fSj_mayer             cpu_abort(env, "Critical interrupt while in user mode. "
1384e1833e1fSj_mayer                       "Aborting\n");
1385e1833e1fSj_mayer             break;
1386e1833e1fSj_mayer         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
1387e1833e1fSj_mayer             cpu_abort(env, "Machine check exception while in user mode. "
1388e1833e1fSj_mayer                       "Aborting\n");
1389e1833e1fSj_mayer             break;
1390e1833e1fSj_mayer         case POWERPC_EXCP_DSI:      /* Data storage exception                */
139190e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
1392e1833e1fSj_mayer                       env->spr[SPR_DAR]);
1393e1833e1fSj_mayer             /* XXX: check this. Seems bugged */
1394e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1395e1833e1fSj_mayer             case 0x40000000:
1396e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1397e1833e1fSj_mayer                 info.si_errno = 0;
1398e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1399e1833e1fSj_mayer                 break;
1400e1833e1fSj_mayer             case 0x04000000:
1401e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1402e1833e1fSj_mayer                 info.si_errno = 0;
1403e1833e1fSj_mayer                 info.si_code = TARGET_ILL_ILLADR;
1404e1833e1fSj_mayer                 break;
1405e1833e1fSj_mayer             case 0x08000000:
1406e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1407e1833e1fSj_mayer                 info.si_errno = 0;
1408e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1409e1833e1fSj_mayer                 break;
1410e1833e1fSj_mayer             default:
1411e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1412e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1413e1833e1fSj_mayer                           env->error_code);
1414e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1415e1833e1fSj_mayer                 info.si_errno = 0;
1416e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1417e1833e1fSj_mayer                 break;
1418e1833e1fSj_mayer             }
1419e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip;
1420624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1421e1833e1fSj_mayer             break;
1422e1833e1fSj_mayer         case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
142390e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
142490e189ecSBlue Swirl                       "\n", env->spr[SPR_SRR0]);
1425e1833e1fSj_mayer             /* XXX: check this */
1426e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1427e1833e1fSj_mayer             case 0x40000000:
1428e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1429e1833e1fSj_mayer             info.si_errno = 0;
1430e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1431e1833e1fSj_mayer                 break;
1432e1833e1fSj_mayer             case 0x10000000:
1433e1833e1fSj_mayer             case 0x08000000:
1434e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1435e1833e1fSj_mayer                 info.si_errno = 0;
1436e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1437e1833e1fSj_mayer                 break;
1438e1833e1fSj_mayer             default:
1439e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1440e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1441e1833e1fSj_mayer                           env->error_code);
1442e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1443e1833e1fSj_mayer                 info.si_errno = 0;
1444e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1445e1833e1fSj_mayer                 break;
1446e1833e1fSj_mayer             }
1447e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1448624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1449e1833e1fSj_mayer             break;
1450e1833e1fSj_mayer         case POWERPC_EXCP_EXTERNAL: /* External input                        */
1451e1833e1fSj_mayer             cpu_abort(env, "External interrupt while in user mode. "
1452e1833e1fSj_mayer                       "Aborting\n");
1453e1833e1fSj_mayer             break;
1454e1833e1fSj_mayer         case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
1455e1833e1fSj_mayer             EXCP_DUMP(env, "Unaligned memory access\n");
1456e1833e1fSj_mayer             /* XXX: check this */
1457e1833e1fSj_mayer             info.si_signo = TARGET_SIGBUS;
1458e1833e1fSj_mayer             info.si_errno = 0;
1459e1833e1fSj_mayer             info.si_code = TARGET_BUS_ADRALN;
1460e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1461624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1462e1833e1fSj_mayer             break;
1463e1833e1fSj_mayer         case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
1464e1833e1fSj_mayer             /* XXX: check this */
1465e1833e1fSj_mayer             switch (env->error_code & ~0xF) {
1466e1833e1fSj_mayer             case POWERPC_EXCP_FP:
1467e1833e1fSj_mayer                 EXCP_DUMP(env, "Floating point program exception\n");
1468e1833e1fSj_mayer                 info.si_signo = TARGET_SIGFPE;
1469e1833e1fSj_mayer                 info.si_errno = 0;
1470e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1471e1833e1fSj_mayer                 case POWERPC_EXCP_FP_OX:
1472e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTOVF;
1473e1833e1fSj_mayer                     break;
1474e1833e1fSj_mayer                 case POWERPC_EXCP_FP_UX:
1475e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTUND;
1476e1833e1fSj_mayer                     break;
1477e1833e1fSj_mayer                 case POWERPC_EXCP_FP_ZX:
1478e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXZDZ:
1479e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTDIV;
1480e1833e1fSj_mayer                     break;
1481e1833e1fSj_mayer                 case POWERPC_EXCP_FP_XX:
1482e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTRES;
1483e1833e1fSj_mayer                     break;
1484e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSOFT:
1485e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTINV;
1486e1833e1fSj_mayer                     break;
14877c58044cSj_mayer                 case POWERPC_EXCP_FP_VXSNAN:
1488e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXISI:
1489e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIDI:
1490e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIMZ:
1491e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXVC:
1492e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSQRT:
1493e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXCVI:
1494e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTSUB;
1495e1833e1fSj_mayer                     break;
1496e1833e1fSj_mayer                 default:
1497e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
1498e1833e1fSj_mayer                               env->error_code);
1499e1833e1fSj_mayer                     break;
1500e1833e1fSj_mayer                 }
1501e1833e1fSj_mayer                 break;
1502e1833e1fSj_mayer             case POWERPC_EXCP_INVAL:
1503e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid instruction\n");
1504e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1505e1833e1fSj_mayer                 info.si_errno = 0;
1506e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1507e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_INVAL:
1508e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPC;
1509e1833e1fSj_mayer                     break;
1510e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_LSWX:
1511e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPN;
1512e1833e1fSj_mayer                     break;
1513e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_SPR:
1514e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1515e1833e1fSj_mayer                     break;
1516e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_FP:
1517e1833e1fSj_mayer                     info.si_code = TARGET_ILL_COPROC;
1518e1833e1fSj_mayer                     break;
1519e1833e1fSj_mayer                 default:
1520e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
1521e1833e1fSj_mayer                               env->error_code & 0xF);
1522e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLADR;
1523e1833e1fSj_mayer                     break;
1524e1833e1fSj_mayer                 }
1525e1833e1fSj_mayer                 break;
1526e1833e1fSj_mayer             case POWERPC_EXCP_PRIV:
1527e1833e1fSj_mayer                 EXCP_DUMP(env, "Privilege violation\n");
1528e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1529e1833e1fSj_mayer                 info.si_errno = 0;
1530e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1531e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_OPC:
1532e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1533e1833e1fSj_mayer                     break;
1534e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_REG:
1535e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1536e1833e1fSj_mayer                     break;
1537e1833e1fSj_mayer                 default:
1538e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
1539e1833e1fSj_mayer                               env->error_code & 0xF);
1540e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1541e1833e1fSj_mayer                     break;
1542e1833e1fSj_mayer                 }
1543e1833e1fSj_mayer                 break;
1544e1833e1fSj_mayer             case POWERPC_EXCP_TRAP:
1545e1833e1fSj_mayer                 cpu_abort(env, "Tried to call a TRAP\n");
1546e1833e1fSj_mayer                 break;
1547e1833e1fSj_mayer             default:
1548e1833e1fSj_mayer                 /* Should not happen ! */
1549e1833e1fSj_mayer                 cpu_abort(env, "Unknown program exception (%02x)\n",
1550e1833e1fSj_mayer                           env->error_code);
1551e1833e1fSj_mayer                 break;
1552e1833e1fSj_mayer             }
1553e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1554624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1555e1833e1fSj_mayer             break;
1556e1833e1fSj_mayer         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
1557e1833e1fSj_mayer             EXCP_DUMP(env, "No floating point allowed\n");
1558e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1559e1833e1fSj_mayer             info.si_errno = 0;
1560e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1561e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1562624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1563e1833e1fSj_mayer             break;
1564e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
1565e1833e1fSj_mayer             cpu_abort(env, "Syscall exception while in user mode. "
1566e1833e1fSj_mayer                       "Aborting\n");
1567e1833e1fSj_mayer             break;
1568e1833e1fSj_mayer         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
1569e1833e1fSj_mayer             EXCP_DUMP(env, "No APU instruction allowed\n");
1570e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1571e1833e1fSj_mayer             info.si_errno = 0;
1572e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1573e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1574624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1575e1833e1fSj_mayer             break;
1576e1833e1fSj_mayer         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
1577e1833e1fSj_mayer             cpu_abort(env, "Decrementer interrupt while in user mode. "
1578e1833e1fSj_mayer                       "Aborting\n");
1579e1833e1fSj_mayer             break;
1580e1833e1fSj_mayer         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
1581e1833e1fSj_mayer             cpu_abort(env, "Fix interval timer interrupt while in user mode. "
1582e1833e1fSj_mayer                       "Aborting\n");
1583e1833e1fSj_mayer             break;
1584e1833e1fSj_mayer         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
1585e1833e1fSj_mayer             cpu_abort(env, "Watchdog timer interrupt while in user mode. "
1586e1833e1fSj_mayer                       "Aborting\n");
1587e1833e1fSj_mayer             break;
1588e1833e1fSj_mayer         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
1589e1833e1fSj_mayer             cpu_abort(env, "Data TLB exception while in user mode. "
1590e1833e1fSj_mayer                       "Aborting\n");
1591e1833e1fSj_mayer             break;
1592e1833e1fSj_mayer         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
1593e1833e1fSj_mayer             cpu_abort(env, "Instruction TLB exception while in user mode. "
1594e1833e1fSj_mayer                       "Aborting\n");
1595e1833e1fSj_mayer             break;
1596e1833e1fSj_mayer         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
1597e1833e1fSj_mayer             EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
1598e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1599e1833e1fSj_mayer             info.si_errno = 0;
1600e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1601e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1602624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1603e1833e1fSj_mayer             break;
1604e1833e1fSj_mayer         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
1605e1833e1fSj_mayer             cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
1606e1833e1fSj_mayer             break;
1607e1833e1fSj_mayer         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
1608e1833e1fSj_mayer             cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
1609e1833e1fSj_mayer             break;
1610e1833e1fSj_mayer         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
1611e1833e1fSj_mayer             cpu_abort(env, "Performance monitor exception not handled\n");
1612e1833e1fSj_mayer             break;
1613e1833e1fSj_mayer         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
1614e1833e1fSj_mayer             cpu_abort(env, "Doorbell interrupt while in user mode. "
1615e1833e1fSj_mayer                        "Aborting\n");
1616e1833e1fSj_mayer             break;
1617e1833e1fSj_mayer         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
1618e1833e1fSj_mayer             cpu_abort(env, "Doorbell critical interrupt while in user mode. "
1619e1833e1fSj_mayer                       "Aborting\n");
1620e1833e1fSj_mayer             break;
1621e1833e1fSj_mayer         case POWERPC_EXCP_RESET:    /* System reset exception                */
1622e1833e1fSj_mayer             cpu_abort(env, "Reset interrupt while in user mode. "
1623e1833e1fSj_mayer                       "Aborting\n");
1624e1833e1fSj_mayer             break;
1625e1833e1fSj_mayer         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
1626e1833e1fSj_mayer             cpu_abort(env, "Data segment exception while in user mode. "
1627e1833e1fSj_mayer                       "Aborting\n");
1628e1833e1fSj_mayer             break;
1629e1833e1fSj_mayer         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
1630e1833e1fSj_mayer             cpu_abort(env, "Instruction segment exception "
1631e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1632e1833e1fSj_mayer             break;
1633e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1634e1833e1fSj_mayer         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
1635e1833e1fSj_mayer             cpu_abort(env, "Hypervisor decrementer interrupt "
1636e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1637e1833e1fSj_mayer             break;
1638e1833e1fSj_mayer         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
1639e1833e1fSj_mayer             /* Nothing to do:
1640e1833e1fSj_mayer              * we use this exception to emulate step-by-step execution mode.
1641e1833e1fSj_mayer              */
1642e1833e1fSj_mayer             break;
1643e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1644e1833e1fSj_mayer         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
1645e1833e1fSj_mayer             cpu_abort(env, "Hypervisor data storage exception "
1646e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1647e1833e1fSj_mayer             break;
1648e1833e1fSj_mayer         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
1649e1833e1fSj_mayer             cpu_abort(env, "Hypervisor instruction storage exception "
1650e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1651e1833e1fSj_mayer             break;
1652e1833e1fSj_mayer         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
1653e1833e1fSj_mayer             cpu_abort(env, "Hypervisor data segment exception "
1654e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1655e1833e1fSj_mayer             break;
1656e1833e1fSj_mayer         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
1657e1833e1fSj_mayer             cpu_abort(env, "Hypervisor instruction segment exception "
1658e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1659e1833e1fSj_mayer             break;
1660e1833e1fSj_mayer         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
1661e1833e1fSj_mayer             EXCP_DUMP(env, "No Altivec instructions allowed\n");
1662e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1663e1833e1fSj_mayer             info.si_errno = 0;
1664e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1665e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1666624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1667e1833e1fSj_mayer             break;
1668e1833e1fSj_mayer         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
1669b4916d7bSDong Xu Wang             cpu_abort(env, "Programmable interval timer interrupt "
1670e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1671e1833e1fSj_mayer             break;
1672e1833e1fSj_mayer         case POWERPC_EXCP_IO:       /* IO error exception                    */
1673e1833e1fSj_mayer             cpu_abort(env, "IO error exception while in user mode. "
1674e1833e1fSj_mayer                       "Aborting\n");
1675e1833e1fSj_mayer             break;
1676e1833e1fSj_mayer         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
1677e1833e1fSj_mayer             cpu_abort(env, "Run mode exception while in user mode. "
1678e1833e1fSj_mayer                       "Aborting\n");
1679e1833e1fSj_mayer             break;
1680e1833e1fSj_mayer         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
1681e1833e1fSj_mayer             cpu_abort(env, "Emulation trap exception not handled\n");
1682e1833e1fSj_mayer             break;
1683e1833e1fSj_mayer         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
1684e1833e1fSj_mayer             cpu_abort(env, "Instruction fetch TLB exception "
1685e1833e1fSj_mayer                       "while in user-mode. Aborting");
1686e1833e1fSj_mayer             break;
1687e1833e1fSj_mayer         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
1688e1833e1fSj_mayer             cpu_abort(env, "Data load TLB exception while in user-mode. "
1689e1833e1fSj_mayer                       "Aborting");
1690e1833e1fSj_mayer             break;
1691e1833e1fSj_mayer         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
1692e1833e1fSj_mayer             cpu_abort(env, "Data store TLB exception while in user-mode. "
1693e1833e1fSj_mayer                       "Aborting");
1694e1833e1fSj_mayer             break;
1695e1833e1fSj_mayer         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
1696e1833e1fSj_mayer             cpu_abort(env, "Floating-point assist exception not handled\n");
1697e1833e1fSj_mayer             break;
1698e1833e1fSj_mayer         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
1699e1833e1fSj_mayer             cpu_abort(env, "Instruction address breakpoint exception "
1700e1833e1fSj_mayer                       "not handled\n");
1701e1833e1fSj_mayer             break;
1702e1833e1fSj_mayer         case POWERPC_EXCP_SMI:      /* System management interrupt           */
1703e1833e1fSj_mayer             cpu_abort(env, "System management interrupt while in user mode. "
1704e1833e1fSj_mayer                       "Aborting\n");
1705e1833e1fSj_mayer             break;
1706e1833e1fSj_mayer         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
1707e1833e1fSj_mayer             cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
1708e1833e1fSj_mayer                       "Aborting\n");
1709e1833e1fSj_mayer             break;
1710e1833e1fSj_mayer         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
1711e1833e1fSj_mayer             cpu_abort(env, "Performance monitor exception not handled\n");
1712e1833e1fSj_mayer             break;
1713e1833e1fSj_mayer         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
1714e1833e1fSj_mayer             cpu_abort(env, "Vector assist exception not handled\n");
1715e1833e1fSj_mayer             break;
1716e1833e1fSj_mayer         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
1717e1833e1fSj_mayer             cpu_abort(env, "Soft patch exception not handled\n");
1718e1833e1fSj_mayer             break;
1719e1833e1fSj_mayer         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
1720e1833e1fSj_mayer             cpu_abort(env, "Maintenance exception while in user mode. "
1721e1833e1fSj_mayer                       "Aborting\n");
1722e1833e1fSj_mayer             break;
1723e1833e1fSj_mayer         case POWERPC_EXCP_STOP:     /* stop translation                      */
1724e1833e1fSj_mayer             /* We did invalidate the instruction cache. Go on */
1725e1833e1fSj_mayer             break;
1726e1833e1fSj_mayer         case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
1727e1833e1fSj_mayer             /* We just stopped because of a branch. Go on */
1728e1833e1fSj_mayer             break;
1729e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL_USER:
1730e1833e1fSj_mayer             /* system call in user-mode emulation */
173167867308Sbellard             /* WARNING:
173267867308Sbellard              * PPC ABI uses overflow flag in cr0 to signal an error
173367867308Sbellard              * in syscalls.
173467867308Sbellard              */
173567867308Sbellard             env->crf[0] &= ~0x1;
173667867308Sbellard             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
173767867308Sbellard                              env->gpr[5], env->gpr[6], env->gpr[7],
17385945cfcbSPeter Maydell                              env->gpr[8], 0, 0);
17399e0e2f96SRichard Henderson             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
1740bcd4933aSNathan Froyd                 /* Returning from a successful sigreturn syscall.
1741bcd4933aSNathan Froyd                    Avoid corrupting register state.  */
1742bcd4933aSNathan Froyd                 break;
1743bcd4933aSNathan Froyd             }
17449e0e2f96SRichard Henderson             if (ret > (target_ulong)(-515)) {
174567867308Sbellard                 env->crf[0] |= 0x1;
174667867308Sbellard                 ret = -ret;
174767867308Sbellard             }
174867867308Sbellard             env->gpr[3] = ret;
174961190b14Sbellard             break;
175056f066bbSNathan Froyd         case POWERPC_EXCP_STCX:
175156f066bbSNathan Froyd             if (do_store_exclusive(env)) {
175256f066bbSNathan Froyd                 info.si_signo = TARGET_SIGSEGV;
175356f066bbSNathan Froyd                 info.si_errno = 0;
175456f066bbSNathan Froyd                 info.si_code = TARGET_SEGV_MAPERR;
175556f066bbSNathan Froyd                 info._sifields._sigfault._addr = env->nip;
175656f066bbSNathan Froyd                 queue_signal(env, info.si_signo, &info);
175756f066bbSNathan Froyd             }
175856f066bbSNathan Froyd             break;
175971f75756Saurel32         case EXCP_DEBUG:
176071f75756Saurel32             {
176171f75756Saurel32                 int sig;
176271f75756Saurel32 
176371f75756Saurel32                 sig = gdb_handlesig(env, TARGET_SIGTRAP);
176471f75756Saurel32                 if (sig) {
176571f75756Saurel32                     info.si_signo = sig;
176671f75756Saurel32                     info.si_errno = 0;
176771f75756Saurel32                     info.si_code = TARGET_TRAP_BRKPT;
176871f75756Saurel32                     queue_signal(env, info.si_signo, &info);
176971f75756Saurel32                   }
177071f75756Saurel32             }
177171f75756Saurel32             break;
177256ba31ffSj_mayer         case EXCP_INTERRUPT:
177356ba31ffSj_mayer             /* just indicate that signals should be handled asap */
177456ba31ffSj_mayer             break;
177561190b14Sbellard         default:
1776e1833e1fSj_mayer             cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
177767867308Sbellard             break;
177867867308Sbellard         }
177967867308Sbellard         process_pending_signals(env);
178067867308Sbellard     }
178167867308Sbellard }
178267867308Sbellard #endif
178367867308Sbellard 
1784048f6b4dSbellard #ifdef TARGET_MIPS
1785048f6b4dSbellard 
1786048f6b4dSbellard #define MIPS_SYS(name, args) args,
1787048f6b4dSbellard 
1788048f6b4dSbellard static const uint8_t mips_syscall_args[] = {
178929fb0f25SAn-Cheng Huang 	MIPS_SYS(sys_syscall	, 8)	/* 4000 */
1790048f6b4dSbellard 	MIPS_SYS(sys_exit	, 1)
1791048f6b4dSbellard 	MIPS_SYS(sys_fork	, 0)
1792048f6b4dSbellard 	MIPS_SYS(sys_read	, 3)
1793048f6b4dSbellard 	MIPS_SYS(sys_write	, 3)
1794048f6b4dSbellard 	MIPS_SYS(sys_open	, 3)	/* 4005 */
1795048f6b4dSbellard 	MIPS_SYS(sys_close	, 1)
1796048f6b4dSbellard 	MIPS_SYS(sys_waitpid	, 3)
1797048f6b4dSbellard 	MIPS_SYS(sys_creat	, 2)
1798048f6b4dSbellard 	MIPS_SYS(sys_link	, 2)
1799048f6b4dSbellard 	MIPS_SYS(sys_unlink	, 1)	/* 4010 */
1800048f6b4dSbellard 	MIPS_SYS(sys_execve	, 0)
1801048f6b4dSbellard 	MIPS_SYS(sys_chdir	, 1)
1802048f6b4dSbellard 	MIPS_SYS(sys_time	, 1)
1803048f6b4dSbellard 	MIPS_SYS(sys_mknod	, 3)
1804048f6b4dSbellard 	MIPS_SYS(sys_chmod	, 2)	/* 4015 */
1805048f6b4dSbellard 	MIPS_SYS(sys_lchown	, 3)
1806048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1807048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_stat */
1808048f6b4dSbellard 	MIPS_SYS(sys_lseek	, 3)
1809048f6b4dSbellard 	MIPS_SYS(sys_getpid	, 0)	/* 4020 */
1810048f6b4dSbellard 	MIPS_SYS(sys_mount	, 5)
1811048f6b4dSbellard 	MIPS_SYS(sys_oldumount	, 1)
1812048f6b4dSbellard 	MIPS_SYS(sys_setuid	, 1)
1813048f6b4dSbellard 	MIPS_SYS(sys_getuid	, 0)
1814048f6b4dSbellard 	MIPS_SYS(sys_stime	, 1)	/* 4025 */
1815048f6b4dSbellard 	MIPS_SYS(sys_ptrace	, 4)
1816048f6b4dSbellard 	MIPS_SYS(sys_alarm	, 1)
1817048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_fstat */
1818048f6b4dSbellard 	MIPS_SYS(sys_pause	, 0)
1819048f6b4dSbellard 	MIPS_SYS(sys_utime	, 2)	/* 4030 */
1820048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1821048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1822048f6b4dSbellard 	MIPS_SYS(sys_access	, 2)
1823048f6b4dSbellard 	MIPS_SYS(sys_nice	, 1)
1824048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4035 */
1825048f6b4dSbellard 	MIPS_SYS(sys_sync	, 0)
1826048f6b4dSbellard 	MIPS_SYS(sys_kill	, 2)
1827048f6b4dSbellard 	MIPS_SYS(sys_rename	, 2)
1828048f6b4dSbellard 	MIPS_SYS(sys_mkdir	, 2)
1829048f6b4dSbellard 	MIPS_SYS(sys_rmdir	, 1)	/* 4040 */
1830048f6b4dSbellard 	MIPS_SYS(sys_dup		, 1)
1831048f6b4dSbellard 	MIPS_SYS(sys_pipe	, 0)
1832048f6b4dSbellard 	MIPS_SYS(sys_times	, 1)
1833048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1834048f6b4dSbellard 	MIPS_SYS(sys_brk		, 1)	/* 4045 */
1835048f6b4dSbellard 	MIPS_SYS(sys_setgid	, 1)
1836048f6b4dSbellard 	MIPS_SYS(sys_getgid	, 0)
1837048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was signal(2) */
1838048f6b4dSbellard 	MIPS_SYS(sys_geteuid	, 0)
1839048f6b4dSbellard 	MIPS_SYS(sys_getegid	, 0)	/* 4050 */
1840048f6b4dSbellard 	MIPS_SYS(sys_acct	, 0)
1841048f6b4dSbellard 	MIPS_SYS(sys_umount	, 2)
1842048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1843048f6b4dSbellard 	MIPS_SYS(sys_ioctl	, 3)
1844048f6b4dSbellard 	MIPS_SYS(sys_fcntl	, 3)	/* 4055 */
1845048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 2)
1846048f6b4dSbellard 	MIPS_SYS(sys_setpgid	, 2)
1847048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1848048f6b4dSbellard 	MIPS_SYS(sys_olduname	, 1)
1849048f6b4dSbellard 	MIPS_SYS(sys_umask	, 1)	/* 4060 */
1850048f6b4dSbellard 	MIPS_SYS(sys_chroot	, 1)
1851048f6b4dSbellard 	MIPS_SYS(sys_ustat	, 2)
1852048f6b4dSbellard 	MIPS_SYS(sys_dup2	, 2)
1853048f6b4dSbellard 	MIPS_SYS(sys_getppid	, 0)
1854048f6b4dSbellard 	MIPS_SYS(sys_getpgrp	, 0)	/* 4065 */
1855048f6b4dSbellard 	MIPS_SYS(sys_setsid	, 0)
1856048f6b4dSbellard 	MIPS_SYS(sys_sigaction	, 3)
1857048f6b4dSbellard 	MIPS_SYS(sys_sgetmask	, 0)
1858048f6b4dSbellard 	MIPS_SYS(sys_ssetmask	, 1)
1859048f6b4dSbellard 	MIPS_SYS(sys_setreuid	, 2)	/* 4070 */
1860048f6b4dSbellard 	MIPS_SYS(sys_setregid	, 2)
1861048f6b4dSbellard 	MIPS_SYS(sys_sigsuspend	, 0)
1862048f6b4dSbellard 	MIPS_SYS(sys_sigpending	, 1)
1863048f6b4dSbellard 	MIPS_SYS(sys_sethostname	, 2)
1864048f6b4dSbellard 	MIPS_SYS(sys_setrlimit	, 2)	/* 4075 */
1865048f6b4dSbellard 	MIPS_SYS(sys_getrlimit	, 2)
1866048f6b4dSbellard 	MIPS_SYS(sys_getrusage	, 2)
1867048f6b4dSbellard 	MIPS_SYS(sys_gettimeofday, 2)
1868048f6b4dSbellard 	MIPS_SYS(sys_settimeofday, 2)
1869048f6b4dSbellard 	MIPS_SYS(sys_getgroups	, 2)	/* 4080 */
1870048f6b4dSbellard 	MIPS_SYS(sys_setgroups	, 2)
1871048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* old_select */
1872048f6b4dSbellard 	MIPS_SYS(sys_symlink	, 2)
1873048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_lstat */
1874048f6b4dSbellard 	MIPS_SYS(sys_readlink	, 3)	/* 4085 */
1875048f6b4dSbellard 	MIPS_SYS(sys_uselib	, 1)
1876048f6b4dSbellard 	MIPS_SYS(sys_swapon	, 2)
1877048f6b4dSbellard 	MIPS_SYS(sys_reboot	, 3)
1878048f6b4dSbellard 	MIPS_SYS(old_readdir	, 3)
1879048f6b4dSbellard 	MIPS_SYS(old_mmap	, 6)	/* 4090 */
1880048f6b4dSbellard 	MIPS_SYS(sys_munmap	, 2)
1881048f6b4dSbellard 	MIPS_SYS(sys_truncate	, 2)
1882048f6b4dSbellard 	MIPS_SYS(sys_ftruncate	, 2)
1883048f6b4dSbellard 	MIPS_SYS(sys_fchmod	, 2)
1884048f6b4dSbellard 	MIPS_SYS(sys_fchown	, 3)	/* 4095 */
1885048f6b4dSbellard 	MIPS_SYS(sys_getpriority	, 2)
1886048f6b4dSbellard 	MIPS_SYS(sys_setpriority	, 3)
1887048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1888048f6b4dSbellard 	MIPS_SYS(sys_statfs	, 2)
1889048f6b4dSbellard 	MIPS_SYS(sys_fstatfs	, 2)	/* 4100 */
1890048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was ioperm(2) */
1891048f6b4dSbellard 	MIPS_SYS(sys_socketcall	, 2)
1892048f6b4dSbellard 	MIPS_SYS(sys_syslog	, 3)
1893048f6b4dSbellard 	MIPS_SYS(sys_setitimer	, 3)
1894048f6b4dSbellard 	MIPS_SYS(sys_getitimer	, 2)	/* 4105 */
1895048f6b4dSbellard 	MIPS_SYS(sys_newstat	, 2)
1896048f6b4dSbellard 	MIPS_SYS(sys_newlstat	, 2)
1897048f6b4dSbellard 	MIPS_SYS(sys_newfstat	, 2)
1898048f6b4dSbellard 	MIPS_SYS(sys_uname	, 1)
1899048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4110 was iopl(2) */
1900048f6b4dSbellard 	MIPS_SYS(sys_vhangup	, 0)
1901048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_idle() */
1902048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_vm86 */
1903048f6b4dSbellard 	MIPS_SYS(sys_wait4	, 4)
1904048f6b4dSbellard 	MIPS_SYS(sys_swapoff	, 1)	/* 4115 */
1905048f6b4dSbellard 	MIPS_SYS(sys_sysinfo	, 1)
1906048f6b4dSbellard 	MIPS_SYS(sys_ipc		, 6)
1907048f6b4dSbellard 	MIPS_SYS(sys_fsync	, 1)
1908048f6b4dSbellard 	MIPS_SYS(sys_sigreturn	, 0)
190918113962SPaul Brook 	MIPS_SYS(sys_clone	, 6)	/* 4120 */
1910048f6b4dSbellard 	MIPS_SYS(sys_setdomainname, 2)
1911048f6b4dSbellard 	MIPS_SYS(sys_newuname	, 1)
1912048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_modify_ldt */
1913048f6b4dSbellard 	MIPS_SYS(sys_adjtimex	, 1)
1914048f6b4dSbellard 	MIPS_SYS(sys_mprotect	, 3)	/* 4125 */
1915048f6b4dSbellard 	MIPS_SYS(sys_sigprocmask	, 3)
1916048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was create_module */
1917048f6b4dSbellard 	MIPS_SYS(sys_init_module	, 5)
1918048f6b4dSbellard 	MIPS_SYS(sys_delete_module, 1)
1919048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4130	was get_kernel_syms */
1920048f6b4dSbellard 	MIPS_SYS(sys_quotactl	, 0)
1921048f6b4dSbellard 	MIPS_SYS(sys_getpgid	, 1)
1922048f6b4dSbellard 	MIPS_SYS(sys_fchdir	, 1)
1923048f6b4dSbellard 	MIPS_SYS(sys_bdflush	, 2)
1924048f6b4dSbellard 	MIPS_SYS(sys_sysfs	, 3)	/* 4135 */
1925048f6b4dSbellard 	MIPS_SYS(sys_personality	, 1)
1926048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* for afs_syscall */
1927048f6b4dSbellard 	MIPS_SYS(sys_setfsuid	, 1)
1928048f6b4dSbellard 	MIPS_SYS(sys_setfsgid	, 1)
1929048f6b4dSbellard 	MIPS_SYS(sys_llseek	, 5)	/* 4140 */
1930048f6b4dSbellard 	MIPS_SYS(sys_getdents	, 3)
1931048f6b4dSbellard 	MIPS_SYS(sys_select	, 5)
1932048f6b4dSbellard 	MIPS_SYS(sys_flock	, 2)
1933048f6b4dSbellard 	MIPS_SYS(sys_msync	, 3)
1934048f6b4dSbellard 	MIPS_SYS(sys_readv	, 3)	/* 4145 */
1935048f6b4dSbellard 	MIPS_SYS(sys_writev	, 3)
1936048f6b4dSbellard 	MIPS_SYS(sys_cacheflush	, 3)
1937048f6b4dSbellard 	MIPS_SYS(sys_cachectl	, 3)
1938048f6b4dSbellard 	MIPS_SYS(sys_sysmips	, 4)
1939048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4150 */
1940048f6b4dSbellard 	MIPS_SYS(sys_getsid	, 1)
1941048f6b4dSbellard 	MIPS_SYS(sys_fdatasync	, 0)
1942048f6b4dSbellard 	MIPS_SYS(sys_sysctl	, 1)
1943048f6b4dSbellard 	MIPS_SYS(sys_mlock	, 2)
1944048f6b4dSbellard 	MIPS_SYS(sys_munlock	, 2)	/* 4155 */
1945048f6b4dSbellard 	MIPS_SYS(sys_mlockall	, 1)
1946048f6b4dSbellard 	MIPS_SYS(sys_munlockall	, 0)
1947048f6b4dSbellard 	MIPS_SYS(sys_sched_setparam, 2)
1948048f6b4dSbellard 	MIPS_SYS(sys_sched_getparam, 2)
1949048f6b4dSbellard 	MIPS_SYS(sys_sched_setscheduler, 3)	/* 4160 */
1950048f6b4dSbellard 	MIPS_SYS(sys_sched_getscheduler, 1)
1951048f6b4dSbellard 	MIPS_SYS(sys_sched_yield	, 0)
1952048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_max, 1)
1953048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_min, 1)
1954048f6b4dSbellard 	MIPS_SYS(sys_sched_rr_get_interval, 2)	/* 4165 */
1955048f6b4dSbellard 	MIPS_SYS(sys_nanosleep,	2)
1956048f6b4dSbellard 	MIPS_SYS(sys_mremap	, 4)
1957048f6b4dSbellard 	MIPS_SYS(sys_accept	, 3)
1958048f6b4dSbellard 	MIPS_SYS(sys_bind	, 3)
1959048f6b4dSbellard 	MIPS_SYS(sys_connect	, 3)	/* 4170 */
1960048f6b4dSbellard 	MIPS_SYS(sys_getpeername	, 3)
1961048f6b4dSbellard 	MIPS_SYS(sys_getsockname	, 3)
1962048f6b4dSbellard 	MIPS_SYS(sys_getsockopt	, 5)
1963048f6b4dSbellard 	MIPS_SYS(sys_listen	, 2)
1964048f6b4dSbellard 	MIPS_SYS(sys_recv	, 4)	/* 4175 */
1965048f6b4dSbellard 	MIPS_SYS(sys_recvfrom	, 6)
1966048f6b4dSbellard 	MIPS_SYS(sys_recvmsg	, 3)
1967048f6b4dSbellard 	MIPS_SYS(sys_send	, 4)
1968048f6b4dSbellard 	MIPS_SYS(sys_sendmsg	, 3)
1969048f6b4dSbellard 	MIPS_SYS(sys_sendto	, 6)	/* 4180 */
1970048f6b4dSbellard 	MIPS_SYS(sys_setsockopt	, 5)
1971048f6b4dSbellard 	MIPS_SYS(sys_shutdown	, 2)
1972048f6b4dSbellard 	MIPS_SYS(sys_socket	, 3)
1973048f6b4dSbellard 	MIPS_SYS(sys_socketpair	, 4)
1974048f6b4dSbellard 	MIPS_SYS(sys_setresuid	, 3)	/* 4185 */
1975048f6b4dSbellard 	MIPS_SYS(sys_getresuid	, 3)
1976048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_query_module */
1977048f6b4dSbellard 	MIPS_SYS(sys_poll	, 3)
1978048f6b4dSbellard 	MIPS_SYS(sys_nfsservctl	, 3)
1979048f6b4dSbellard 	MIPS_SYS(sys_setresgid	, 3)	/* 4190 */
1980048f6b4dSbellard 	MIPS_SYS(sys_getresgid	, 3)
1981048f6b4dSbellard 	MIPS_SYS(sys_prctl	, 5)
1982048f6b4dSbellard 	MIPS_SYS(sys_rt_sigreturn, 0)
1983048f6b4dSbellard 	MIPS_SYS(sys_rt_sigaction, 4)
1984048f6b4dSbellard 	MIPS_SYS(sys_rt_sigprocmask, 4)	/* 4195 */
1985048f6b4dSbellard 	MIPS_SYS(sys_rt_sigpending, 2)
1986048f6b4dSbellard 	MIPS_SYS(sys_rt_sigtimedwait, 4)
1987048f6b4dSbellard 	MIPS_SYS(sys_rt_sigqueueinfo, 3)
1988048f6b4dSbellard 	MIPS_SYS(sys_rt_sigsuspend, 0)
1989048f6b4dSbellard 	MIPS_SYS(sys_pread64	, 6)	/* 4200 */
1990048f6b4dSbellard 	MIPS_SYS(sys_pwrite64	, 6)
1991048f6b4dSbellard 	MIPS_SYS(sys_chown	, 3)
1992048f6b4dSbellard 	MIPS_SYS(sys_getcwd	, 2)
1993048f6b4dSbellard 	MIPS_SYS(sys_capget	, 2)
1994048f6b4dSbellard 	MIPS_SYS(sys_capset	, 2)	/* 4205 */
1995053ebb27SWesley W. Terpstra 	MIPS_SYS(sys_sigaltstack	, 2)
1996048f6b4dSbellard 	MIPS_SYS(sys_sendfile	, 4)
1997048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1998048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1999048f6b4dSbellard 	MIPS_SYS(sys_mmap2	, 6)	/* 4210 */
2000048f6b4dSbellard 	MIPS_SYS(sys_truncate64	, 4)
2001048f6b4dSbellard 	MIPS_SYS(sys_ftruncate64	, 4)
2002048f6b4dSbellard 	MIPS_SYS(sys_stat64	, 2)
2003048f6b4dSbellard 	MIPS_SYS(sys_lstat64	, 2)
2004048f6b4dSbellard 	MIPS_SYS(sys_fstat64	, 2)	/* 4215 */
2005048f6b4dSbellard 	MIPS_SYS(sys_pivot_root	, 2)
2006048f6b4dSbellard 	MIPS_SYS(sys_mincore	, 3)
2007048f6b4dSbellard 	MIPS_SYS(sys_madvise	, 3)
2008048f6b4dSbellard 	MIPS_SYS(sys_getdents64	, 3)
2009048f6b4dSbellard 	MIPS_SYS(sys_fcntl64	, 3)	/* 4220 */
2010048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
2011048f6b4dSbellard 	MIPS_SYS(sys_gettid	, 0)
2012048f6b4dSbellard 	MIPS_SYS(sys_readahead	, 5)
2013048f6b4dSbellard 	MIPS_SYS(sys_setxattr	, 5)
2014048f6b4dSbellard 	MIPS_SYS(sys_lsetxattr	, 5)	/* 4225 */
2015048f6b4dSbellard 	MIPS_SYS(sys_fsetxattr	, 5)
2016048f6b4dSbellard 	MIPS_SYS(sys_getxattr	, 4)
2017048f6b4dSbellard 	MIPS_SYS(sys_lgetxattr	, 4)
2018048f6b4dSbellard 	MIPS_SYS(sys_fgetxattr	, 4)
2019048f6b4dSbellard 	MIPS_SYS(sys_listxattr	, 3)	/* 4230 */
2020048f6b4dSbellard 	MIPS_SYS(sys_llistxattr	, 3)
2021048f6b4dSbellard 	MIPS_SYS(sys_flistxattr	, 3)
2022048f6b4dSbellard 	MIPS_SYS(sys_removexattr	, 2)
2023048f6b4dSbellard 	MIPS_SYS(sys_lremovexattr, 2)
2024048f6b4dSbellard 	MIPS_SYS(sys_fremovexattr, 2)	/* 4235 */
2025048f6b4dSbellard 	MIPS_SYS(sys_tkill	, 2)
2026048f6b4dSbellard 	MIPS_SYS(sys_sendfile64	, 5)
2027048f6b4dSbellard 	MIPS_SYS(sys_futex	, 2)
2028048f6b4dSbellard 	MIPS_SYS(sys_sched_setaffinity, 3)
2029048f6b4dSbellard 	MIPS_SYS(sys_sched_getaffinity, 3)	/* 4240 */
2030048f6b4dSbellard 	MIPS_SYS(sys_io_setup	, 2)
2031048f6b4dSbellard 	MIPS_SYS(sys_io_destroy	, 1)
2032048f6b4dSbellard 	MIPS_SYS(sys_io_getevents, 5)
2033048f6b4dSbellard 	MIPS_SYS(sys_io_submit	, 3)
2034048f6b4dSbellard 	MIPS_SYS(sys_io_cancel	, 3)	/* 4245 */
2035048f6b4dSbellard 	MIPS_SYS(sys_exit_group	, 1)
2036048f6b4dSbellard 	MIPS_SYS(sys_lookup_dcookie, 3)
2037048f6b4dSbellard 	MIPS_SYS(sys_epoll_create, 1)
2038048f6b4dSbellard 	MIPS_SYS(sys_epoll_ctl	, 4)
2039048f6b4dSbellard 	MIPS_SYS(sys_epoll_wait	, 3)	/* 4250 */
2040048f6b4dSbellard 	MIPS_SYS(sys_remap_file_pages, 5)
2041048f6b4dSbellard 	MIPS_SYS(sys_set_tid_address, 1)
2042048f6b4dSbellard 	MIPS_SYS(sys_restart_syscall, 0)
2043048f6b4dSbellard 	MIPS_SYS(sys_fadvise64_64, 7)
2044048f6b4dSbellard 	MIPS_SYS(sys_statfs64	, 3)	/* 4255 */
2045048f6b4dSbellard 	MIPS_SYS(sys_fstatfs64	, 2)
2046048f6b4dSbellard 	MIPS_SYS(sys_timer_create, 3)
2047048f6b4dSbellard 	MIPS_SYS(sys_timer_settime, 4)
2048048f6b4dSbellard 	MIPS_SYS(sys_timer_gettime, 2)
2049048f6b4dSbellard 	MIPS_SYS(sys_timer_getoverrun, 1)	/* 4260 */
2050048f6b4dSbellard 	MIPS_SYS(sys_timer_delete, 1)
2051048f6b4dSbellard 	MIPS_SYS(sys_clock_settime, 2)
2052048f6b4dSbellard 	MIPS_SYS(sys_clock_gettime, 2)
2053048f6b4dSbellard 	MIPS_SYS(sys_clock_getres, 2)
2054048f6b4dSbellard 	MIPS_SYS(sys_clock_nanosleep, 4)	/* 4265 */
2055048f6b4dSbellard 	MIPS_SYS(sys_tgkill	, 3)
2056048f6b4dSbellard 	MIPS_SYS(sys_utimes	, 2)
2057048f6b4dSbellard 	MIPS_SYS(sys_mbind	, 4)
2058048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_get_mempolicy */
2059048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4270 sys_set_mempolicy */
2060048f6b4dSbellard 	MIPS_SYS(sys_mq_open	, 4)
2061048f6b4dSbellard 	MIPS_SYS(sys_mq_unlink	, 1)
2062048f6b4dSbellard 	MIPS_SYS(sys_mq_timedsend, 5)
2063048f6b4dSbellard 	MIPS_SYS(sys_mq_timedreceive, 5)
2064048f6b4dSbellard 	MIPS_SYS(sys_mq_notify	, 2)	/* 4275 */
2065048f6b4dSbellard 	MIPS_SYS(sys_mq_getsetattr, 3)
2066048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_vserver */
2067048f6b4dSbellard 	MIPS_SYS(sys_waitid	, 4)
2068048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
2069048f6b4dSbellard 	MIPS_SYS(sys_add_key	, 5)
2070048f6b4dSbellard 	MIPS_SYS(sys_request_key, 4)
2071048f6b4dSbellard 	MIPS_SYS(sys_keyctl	, 5)
20726f5b89a0Sths 	MIPS_SYS(sys_set_thread_area, 1)
2073388bb21aSths 	MIPS_SYS(sys_inotify_init, 0)
2074388bb21aSths 	MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
2075388bb21aSths 	MIPS_SYS(sys_inotify_rm_watch, 2)
2076388bb21aSths 	MIPS_SYS(sys_migrate_pages, 4)
2077388bb21aSths 	MIPS_SYS(sys_openat, 4)
2078388bb21aSths 	MIPS_SYS(sys_mkdirat, 3)
2079388bb21aSths 	MIPS_SYS(sys_mknodat, 4)	/* 4290 */
2080388bb21aSths 	MIPS_SYS(sys_fchownat, 5)
2081388bb21aSths 	MIPS_SYS(sys_futimesat, 3)
2082388bb21aSths 	MIPS_SYS(sys_fstatat64, 4)
2083388bb21aSths 	MIPS_SYS(sys_unlinkat, 3)
2084388bb21aSths 	MIPS_SYS(sys_renameat, 4)	/* 4295 */
2085388bb21aSths 	MIPS_SYS(sys_linkat, 5)
2086388bb21aSths 	MIPS_SYS(sys_symlinkat, 3)
2087388bb21aSths 	MIPS_SYS(sys_readlinkat, 4)
2088388bb21aSths 	MIPS_SYS(sys_fchmodat, 3)
2089388bb21aSths 	MIPS_SYS(sys_faccessat, 3)	/* 4300 */
2090388bb21aSths 	MIPS_SYS(sys_pselect6, 6)
2091388bb21aSths 	MIPS_SYS(sys_ppoll, 5)
2092388bb21aSths 	MIPS_SYS(sys_unshare, 1)
2093388bb21aSths 	MIPS_SYS(sys_splice, 4)
2094388bb21aSths 	MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
2095388bb21aSths 	MIPS_SYS(sys_tee, 4)
2096388bb21aSths 	MIPS_SYS(sys_vmsplice, 4)
2097388bb21aSths 	MIPS_SYS(sys_move_pages, 6)
2098388bb21aSths 	MIPS_SYS(sys_set_robust_list, 2)
2099388bb21aSths 	MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
2100388bb21aSths 	MIPS_SYS(sys_kexec_load, 4)
2101388bb21aSths 	MIPS_SYS(sys_getcpu, 3)
2102388bb21aSths 	MIPS_SYS(sys_epoll_pwait, 6)
2103388bb21aSths 	MIPS_SYS(sys_ioprio_set, 3)
2104388bb21aSths 	MIPS_SYS(sys_ioprio_get, 2)
2105d979e8ebSPeter Maydell         MIPS_SYS(sys_utimensat, 4)
2106d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd, 3)
2107d979e8ebSPeter Maydell         MIPS_SYS(sys_ni_syscall, 0)     /* was timerfd */
2108d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd, 1)
2109d979e8ebSPeter Maydell         MIPS_SYS(sys_fallocate, 6)      /* 4320 */
2110d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_create, 2)
2111d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_gettime, 2)
2112d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_settime, 4)
2113d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd4, 4)
2114d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd2, 2)       /* 4325 */
2115d979e8ebSPeter Maydell         MIPS_SYS(sys_epoll_create1, 1)
2116d979e8ebSPeter Maydell         MIPS_SYS(sys_dup3, 3)
2117d979e8ebSPeter Maydell         MIPS_SYS(sys_pipe2, 2)
2118d979e8ebSPeter Maydell         MIPS_SYS(sys_inotify_init1, 1)
2119d979e8ebSPeter Maydell         MIPS_SYS(sys_preadv, 6)         /* 4330 */
2120d979e8ebSPeter Maydell         MIPS_SYS(sys_pwritev, 6)
2121d979e8ebSPeter Maydell         MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
2122d979e8ebSPeter Maydell         MIPS_SYS(sys_perf_event_open, 5)
2123d979e8ebSPeter Maydell         MIPS_SYS(sys_accept4, 4)
2124d979e8ebSPeter Maydell         MIPS_SYS(sys_recvmmsg, 5)       /* 4335 */
2125d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_init, 2)
2126d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_mark, 6)
2127d979e8ebSPeter Maydell         MIPS_SYS(sys_prlimit64, 4)
2128d979e8ebSPeter Maydell         MIPS_SYS(sys_name_to_handle_at, 5)
2129d979e8ebSPeter Maydell         MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
2130d979e8ebSPeter Maydell         MIPS_SYS(sys_clock_adjtime, 2)
2131d979e8ebSPeter Maydell         MIPS_SYS(sys_syncfs, 1)
2132048f6b4dSbellard };
2133048f6b4dSbellard 
2134048f6b4dSbellard #undef MIPS_SYS
2135048f6b4dSbellard 
2136590bc601SPaul Brook static int do_store_exclusive(CPUMIPSState *env)
2137590bc601SPaul Brook {
2138590bc601SPaul Brook     target_ulong addr;
2139590bc601SPaul Brook     target_ulong page_addr;
2140590bc601SPaul Brook     target_ulong val;
2141590bc601SPaul Brook     int flags;
2142590bc601SPaul Brook     int segv = 0;
2143590bc601SPaul Brook     int reg;
2144590bc601SPaul Brook     int d;
2145590bc601SPaul Brook 
21465499b6ffSAurelien Jarno     addr = env->lladdr;
2147590bc601SPaul Brook     page_addr = addr & TARGET_PAGE_MASK;
2148590bc601SPaul Brook     start_exclusive();
2149590bc601SPaul Brook     mmap_lock();
2150590bc601SPaul Brook     flags = page_get_flags(page_addr);
2151590bc601SPaul Brook     if ((flags & PAGE_READ) == 0) {
2152590bc601SPaul Brook         segv = 1;
2153590bc601SPaul Brook     } else {
2154590bc601SPaul Brook         reg = env->llreg & 0x1f;
2155590bc601SPaul Brook         d = (env->llreg & 0x20) != 0;
2156590bc601SPaul Brook         if (d) {
2157590bc601SPaul Brook             segv = get_user_s64(val, addr);
2158590bc601SPaul Brook         } else {
2159590bc601SPaul Brook             segv = get_user_s32(val, addr);
2160590bc601SPaul Brook         }
2161590bc601SPaul Brook         if (!segv) {
2162590bc601SPaul Brook             if (val != env->llval) {
2163590bc601SPaul Brook                 env->active_tc.gpr[reg] = 0;
2164590bc601SPaul Brook             } else {
2165590bc601SPaul Brook                 if (d) {
2166590bc601SPaul Brook                     segv = put_user_u64(env->llnewval, addr);
2167590bc601SPaul Brook                 } else {
2168590bc601SPaul Brook                     segv = put_user_u32(env->llnewval, addr);
2169590bc601SPaul Brook                 }
2170590bc601SPaul Brook                 if (!segv) {
2171590bc601SPaul Brook                     env->active_tc.gpr[reg] = 1;
2172590bc601SPaul Brook                 }
2173590bc601SPaul Brook             }
2174590bc601SPaul Brook         }
2175590bc601SPaul Brook     }
21765499b6ffSAurelien Jarno     env->lladdr = -1;
2177590bc601SPaul Brook     if (!segv) {
2178590bc601SPaul Brook         env->active_tc.PC += 4;
2179590bc601SPaul Brook     }
2180590bc601SPaul Brook     mmap_unlock();
2181590bc601SPaul Brook     end_exclusive();
2182590bc601SPaul Brook     return segv;
2183590bc601SPaul Brook }
2184590bc601SPaul Brook 
2185048f6b4dSbellard void cpu_loop(CPUMIPSState *env)
2186048f6b4dSbellard {
2187c227f099SAnthony Liguori     target_siginfo_t info;
2188388bb21aSths     int trapnr, ret;
2189048f6b4dSbellard     unsigned int syscall_num;
2190048f6b4dSbellard 
2191048f6b4dSbellard     for(;;) {
2192590bc601SPaul Brook         cpu_exec_start(env);
2193048f6b4dSbellard         trapnr = cpu_mips_exec(env);
2194590bc601SPaul Brook         cpu_exec_end(env);
2195048f6b4dSbellard         switch(trapnr) {
2196048f6b4dSbellard         case EXCP_SYSCALL:
2197b5dc7732Sths             syscall_num = env->active_tc.gpr[2] - 4000;
2198b5dc7732Sths             env->active_tc.PC += 4;
2199048f6b4dSbellard             if (syscall_num >= sizeof(mips_syscall_args)) {
22007c2f6157SWesley W. Terpstra                 ret = -TARGET_ENOSYS;
2201048f6b4dSbellard             } else {
2202388bb21aSths                 int nb_args;
2203992f48a0Sblueswir1                 abi_ulong sp_reg;
2204992f48a0Sblueswir1                 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
2205388bb21aSths 
2206048f6b4dSbellard                 nb_args = mips_syscall_args[syscall_num];
2207b5dc7732Sths                 sp_reg = env->active_tc.gpr[29];
2208388bb21aSths                 switch (nb_args) {
2209048f6b4dSbellard                 /* these arguments are taken from the stack */
221094c19610SAn-Cheng Huang                 case 8:
221194c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
221294c19610SAn-Cheng Huang                         goto done_syscall;
221394c19610SAn-Cheng Huang                     }
221494c19610SAn-Cheng Huang                 case 7:
221594c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
221694c19610SAn-Cheng Huang                         goto done_syscall;
221794c19610SAn-Cheng Huang                     }
221894c19610SAn-Cheng Huang                 case 6:
221994c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
222094c19610SAn-Cheng Huang                         goto done_syscall;
222194c19610SAn-Cheng Huang                     }
222294c19610SAn-Cheng Huang                 case 5:
222394c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
222494c19610SAn-Cheng Huang                         goto done_syscall;
222594c19610SAn-Cheng Huang                     }
2226388bb21aSths                 default:
2227388bb21aSths                     break;
2228048f6b4dSbellard                 }
2229b5dc7732Sths                 ret = do_syscall(env, env->active_tc.gpr[2],
2230b5dc7732Sths                                  env->active_tc.gpr[4],
2231b5dc7732Sths                                  env->active_tc.gpr[5],
2232b5dc7732Sths                                  env->active_tc.gpr[6],
2233b5dc7732Sths                                  env->active_tc.gpr[7],
22345945cfcbSPeter Maydell                                  arg5, arg6, arg7, arg8);
2235048f6b4dSbellard             }
223694c19610SAn-Cheng Huang done_syscall:
22370b1bcb00Spbrook             if (ret == -TARGET_QEMU_ESIGRETURN) {
22380b1bcb00Spbrook                 /* Returning from a successful sigreturn syscall.
22390b1bcb00Spbrook                    Avoid clobbering register state.  */
22400b1bcb00Spbrook                 break;
22410b1bcb00Spbrook             }
2242048f6b4dSbellard             if ((unsigned int)ret >= (unsigned int)(-1133)) {
2243b5dc7732Sths                 env->active_tc.gpr[7] = 1; /* error flag */
2244048f6b4dSbellard                 ret = -ret;
2245048f6b4dSbellard             } else {
2246b5dc7732Sths                 env->active_tc.gpr[7] = 0; /* error flag */
2247388bb21aSths             }
2248b5dc7732Sths             env->active_tc.gpr[2] = ret;
2249048f6b4dSbellard             break;
2250ca7c2b1bSths         case EXCP_TLBL:
2251ca7c2b1bSths         case EXCP_TLBS:
2252e6e5bd2dSWesley W. Terpstra         case EXCP_AdEL:
2253e6e5bd2dSWesley W. Terpstra         case EXCP_AdES:
2254e4474235Spbrook             info.si_signo = TARGET_SIGSEGV;
2255e4474235Spbrook             info.si_errno = 0;
2256e4474235Spbrook             /* XXX: check env->error_code */
2257e4474235Spbrook             info.si_code = TARGET_SEGV_MAPERR;
2258e4474235Spbrook             info._sifields._sigfault._addr = env->CP0_BadVAddr;
2259e4474235Spbrook             queue_signal(env, info.si_signo, &info);
2260e4474235Spbrook             break;
22616900e84bSbellard         case EXCP_CpU:
2262048f6b4dSbellard         case EXCP_RI:
2263048f6b4dSbellard             info.si_signo = TARGET_SIGILL;
2264048f6b4dSbellard             info.si_errno = 0;
2265048f6b4dSbellard             info.si_code = 0;
2266624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2267048f6b4dSbellard             break;
2268106ec879Sbellard         case EXCP_INTERRUPT:
2269106ec879Sbellard             /* just indicate that signals should be handled asap */
2270106ec879Sbellard             break;
2271d08b2a28Spbrook         case EXCP_DEBUG:
2272d08b2a28Spbrook             {
2273d08b2a28Spbrook                 int sig;
2274d08b2a28Spbrook 
2275d08b2a28Spbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2276d08b2a28Spbrook                 if (sig)
2277d08b2a28Spbrook                   {
2278d08b2a28Spbrook                     info.si_signo = sig;
2279d08b2a28Spbrook                     info.si_errno = 0;
2280d08b2a28Spbrook                     info.si_code = TARGET_TRAP_BRKPT;
2281624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2282d08b2a28Spbrook                   }
2283d08b2a28Spbrook             }
2284d08b2a28Spbrook             break;
2285590bc601SPaul Brook         case EXCP_SC:
2286590bc601SPaul Brook             if (do_store_exclusive(env)) {
2287590bc601SPaul Brook                 info.si_signo = TARGET_SIGSEGV;
2288590bc601SPaul Brook                 info.si_errno = 0;
2289590bc601SPaul Brook                 info.si_code = TARGET_SEGV_MAPERR;
2290590bc601SPaul Brook                 info._sifields._sigfault._addr = env->active_tc.PC;
2291590bc601SPaul Brook                 queue_signal(env, info.si_signo, &info);
2292590bc601SPaul Brook             }
2293590bc601SPaul Brook             break;
2294853c3240SJia Liu         case EXCP_DSPDIS:
2295853c3240SJia Liu             info.si_signo = TARGET_SIGILL;
2296853c3240SJia Liu             info.si_errno = 0;
2297853c3240SJia Liu             info.si_code = TARGET_ILL_ILLOPC;
2298853c3240SJia Liu             queue_signal(env, info.si_signo, &info);
2299853c3240SJia Liu             break;
2300048f6b4dSbellard         default:
2301048f6b4dSbellard             //        error:
2302048f6b4dSbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2303048f6b4dSbellard                     trapnr);
2304048f6b4dSbellard             cpu_dump_state(env, stderr, fprintf, 0);
2305048f6b4dSbellard             abort();
2306048f6b4dSbellard         }
2307048f6b4dSbellard         process_pending_signals(env);
2308048f6b4dSbellard     }
2309048f6b4dSbellard }
2310048f6b4dSbellard #endif
2311048f6b4dSbellard 
2312d962783eSJia Liu #ifdef TARGET_OPENRISC
2313d962783eSJia Liu 
2314d962783eSJia Liu void cpu_loop(CPUOpenRISCState *env)
2315d962783eSJia Liu {
2316d962783eSJia Liu     int trapnr, gdbsig;
2317d962783eSJia Liu 
2318d962783eSJia Liu     for (;;) {
2319d962783eSJia Liu         trapnr = cpu_exec(env);
2320d962783eSJia Liu         gdbsig = 0;
2321d962783eSJia Liu 
2322d962783eSJia Liu         switch (trapnr) {
2323d962783eSJia Liu         case EXCP_RESET:
2324d962783eSJia Liu             qemu_log("\nReset request, exit, pc is %#x\n", env->pc);
2325d962783eSJia Liu             exit(1);
2326d962783eSJia Liu             break;
2327d962783eSJia Liu         case EXCP_BUSERR:
2328d962783eSJia Liu             qemu_log("\nBus error, exit, pc is %#x\n", env->pc);
2329d962783eSJia Liu             gdbsig = SIGBUS;
2330d962783eSJia Liu             break;
2331d962783eSJia Liu         case EXCP_DPF:
2332d962783eSJia Liu         case EXCP_IPF:
2333d962783eSJia Liu             cpu_dump_state(env, stderr, fprintf, 0);
2334d962783eSJia Liu             gdbsig = TARGET_SIGSEGV;
2335d962783eSJia Liu             break;
2336d962783eSJia Liu         case EXCP_TICK:
2337d962783eSJia Liu             qemu_log("\nTick time interrupt pc is %#x\n", env->pc);
2338d962783eSJia Liu             break;
2339d962783eSJia Liu         case EXCP_ALIGN:
2340d962783eSJia Liu             qemu_log("\nAlignment pc is %#x\n", env->pc);
2341d962783eSJia Liu             gdbsig = SIGBUS;
2342d962783eSJia Liu             break;
2343d962783eSJia Liu         case EXCP_ILLEGAL:
2344d962783eSJia Liu             qemu_log("\nIllegal instructionpc is %#x\n", env->pc);
2345d962783eSJia Liu             gdbsig = SIGILL;
2346d962783eSJia Liu             break;
2347d962783eSJia Liu         case EXCP_INT:
2348d962783eSJia Liu             qemu_log("\nExternal interruptpc is %#x\n", env->pc);
2349d962783eSJia Liu             break;
2350d962783eSJia Liu         case EXCP_DTLBMISS:
2351d962783eSJia Liu         case EXCP_ITLBMISS:
2352d962783eSJia Liu             qemu_log("\nTLB miss\n");
2353d962783eSJia Liu             break;
2354d962783eSJia Liu         case EXCP_RANGE:
2355d962783eSJia Liu             qemu_log("\nRange\n");
2356d962783eSJia Liu             gdbsig = SIGSEGV;
2357d962783eSJia Liu             break;
2358d962783eSJia Liu         case EXCP_SYSCALL:
2359d962783eSJia Liu             env->pc += 4;   /* 0xc00; */
2360d962783eSJia Liu             env->gpr[11] = do_syscall(env,
2361d962783eSJia Liu                                       env->gpr[11], /* return value       */
2362d962783eSJia Liu                                       env->gpr[3],  /* r3 - r7 are params */
2363d962783eSJia Liu                                       env->gpr[4],
2364d962783eSJia Liu                                       env->gpr[5],
2365d962783eSJia Liu                                       env->gpr[6],
2366d962783eSJia Liu                                       env->gpr[7],
2367d962783eSJia Liu                                       env->gpr[8], 0, 0);
2368d962783eSJia Liu             break;
2369d962783eSJia Liu         case EXCP_FPE:
2370d962783eSJia Liu             qemu_log("\nFloating point error\n");
2371d962783eSJia Liu             break;
2372d962783eSJia Liu         case EXCP_TRAP:
2373d962783eSJia Liu             qemu_log("\nTrap\n");
2374d962783eSJia Liu             gdbsig = SIGTRAP;
2375d962783eSJia Liu             break;
2376d962783eSJia Liu         case EXCP_NR:
2377d962783eSJia Liu             qemu_log("\nNR\n");
2378d962783eSJia Liu             break;
2379d962783eSJia Liu         default:
2380d962783eSJia Liu             qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n",
2381d962783eSJia Liu                      trapnr);
2382d962783eSJia Liu             cpu_dump_state(env, stderr, fprintf, 0);
2383d962783eSJia Liu             gdbsig = TARGET_SIGILL;
2384d962783eSJia Liu             break;
2385d962783eSJia Liu         }
2386d962783eSJia Liu         if (gdbsig) {
2387d962783eSJia Liu             gdb_handlesig(env, gdbsig);
2388d962783eSJia Liu             if (gdbsig != TARGET_SIGTRAP) {
2389d962783eSJia Liu                 exit(1);
2390d962783eSJia Liu             }
2391d962783eSJia Liu         }
2392d962783eSJia Liu 
2393d962783eSJia Liu         process_pending_signals(env);
2394d962783eSJia Liu     }
2395d962783eSJia Liu }
2396d962783eSJia Liu 
2397d962783eSJia Liu #endif /* TARGET_OPENRISC */
2398d962783eSJia Liu 
2399fdf9b3e8Sbellard #ifdef TARGET_SH4
240005390248SAndreas Färber void cpu_loop(CPUSH4State *env)
2401fdf9b3e8Sbellard {
2402fdf9b3e8Sbellard     int trapnr, ret;
2403c227f099SAnthony Liguori     target_siginfo_t info;
2404fdf9b3e8Sbellard 
2405fdf9b3e8Sbellard     while (1) {
2406fdf9b3e8Sbellard         trapnr = cpu_sh4_exec (env);
2407fdf9b3e8Sbellard 
2408fdf9b3e8Sbellard         switch (trapnr) {
2409fdf9b3e8Sbellard         case 0x160:
24100b6d3ae0Saurel32             env->pc += 2;
2411fdf9b3e8Sbellard             ret = do_syscall(env,
24129c2a9ea1Spbrook                              env->gregs[3],
24139c2a9ea1Spbrook                              env->gregs[4],
24149c2a9ea1Spbrook                              env->gregs[5],
24159c2a9ea1Spbrook                              env->gregs[6],
24169c2a9ea1Spbrook                              env->gregs[7],
24179c2a9ea1Spbrook                              env->gregs[0],
24185945cfcbSPeter Maydell                              env->gregs[1],
24195945cfcbSPeter Maydell                              0, 0);
24209c2a9ea1Spbrook             env->gregs[0] = ret;
2421fdf9b3e8Sbellard             break;
2422c3b5bc8aSths         case EXCP_INTERRUPT:
2423c3b5bc8aSths             /* just indicate that signals should be handled asap */
2424c3b5bc8aSths             break;
2425355fb23dSpbrook         case EXCP_DEBUG:
2426355fb23dSpbrook             {
2427355fb23dSpbrook                 int sig;
2428355fb23dSpbrook 
2429355fb23dSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2430355fb23dSpbrook                 if (sig)
2431355fb23dSpbrook                   {
2432355fb23dSpbrook                     info.si_signo = sig;
2433355fb23dSpbrook                     info.si_errno = 0;
2434355fb23dSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2435624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2436355fb23dSpbrook                   }
2437355fb23dSpbrook             }
2438355fb23dSpbrook             break;
2439c3b5bc8aSths 	case 0xa0:
2440c3b5bc8aSths 	case 0xc0:
2441c3b5bc8aSths             info.si_signo = SIGSEGV;
2442c3b5bc8aSths             info.si_errno = 0;
2443c3b5bc8aSths             info.si_code = TARGET_SEGV_MAPERR;
2444c3b5bc8aSths             info._sifields._sigfault._addr = env->tea;
2445624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2446c3b5bc8aSths 	    break;
2447c3b5bc8aSths 
2448fdf9b3e8Sbellard         default:
2449fdf9b3e8Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
2450fdf9b3e8Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
2451fdf9b3e8Sbellard             exit (1);
2452fdf9b3e8Sbellard         }
2453fdf9b3e8Sbellard         process_pending_signals (env);
2454fdf9b3e8Sbellard     }
2455fdf9b3e8Sbellard }
2456fdf9b3e8Sbellard #endif
2457fdf9b3e8Sbellard 
245848733d19Sths #ifdef TARGET_CRIS
245905390248SAndreas Färber void cpu_loop(CPUCRISState *env)
246048733d19Sths {
246148733d19Sths     int trapnr, ret;
2462c227f099SAnthony Liguori     target_siginfo_t info;
246348733d19Sths 
246448733d19Sths     while (1) {
246548733d19Sths         trapnr = cpu_cris_exec (env);
246648733d19Sths         switch (trapnr) {
246748733d19Sths         case 0xaa:
246848733d19Sths             {
246948733d19Sths                 info.si_signo = SIGSEGV;
247048733d19Sths                 info.si_errno = 0;
247148733d19Sths                 /* XXX: check env->error_code */
247248733d19Sths                 info.si_code = TARGET_SEGV_MAPERR;
2473e00c1e71Sedgar_igl                 info._sifields._sigfault._addr = env->pregs[PR_EDA];
2474624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
247548733d19Sths             }
247648733d19Sths             break;
2477b6d3abdaSedgar_igl 	case EXCP_INTERRUPT:
2478b6d3abdaSedgar_igl 	  /* just indicate that signals should be handled asap */
2479b6d3abdaSedgar_igl 	  break;
248048733d19Sths         case EXCP_BREAK:
248148733d19Sths             ret = do_syscall(env,
248248733d19Sths                              env->regs[9],
248348733d19Sths                              env->regs[10],
248448733d19Sths                              env->regs[11],
248548733d19Sths                              env->regs[12],
248648733d19Sths                              env->regs[13],
248748733d19Sths                              env->pregs[7],
24885945cfcbSPeter Maydell                              env->pregs[11],
24895945cfcbSPeter Maydell                              0, 0);
249048733d19Sths             env->regs[10] = ret;
249148733d19Sths             break;
249248733d19Sths         case EXCP_DEBUG:
249348733d19Sths             {
249448733d19Sths                 int sig;
249548733d19Sths 
249648733d19Sths                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
249748733d19Sths                 if (sig)
249848733d19Sths                   {
249948733d19Sths                     info.si_signo = sig;
250048733d19Sths                     info.si_errno = 0;
250148733d19Sths                     info.si_code = TARGET_TRAP_BRKPT;
2502624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
250348733d19Sths                   }
250448733d19Sths             }
250548733d19Sths             break;
250648733d19Sths         default:
250748733d19Sths             printf ("Unhandled trap: 0x%x\n", trapnr);
250848733d19Sths             cpu_dump_state(env, stderr, fprintf, 0);
250948733d19Sths             exit (1);
251048733d19Sths         }
251148733d19Sths         process_pending_signals (env);
251248733d19Sths     }
251348733d19Sths }
251448733d19Sths #endif
251548733d19Sths 
2516b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
251705390248SAndreas Färber void cpu_loop(CPUMBState *env)
2518b779e29eSEdgar E. Iglesias {
2519b779e29eSEdgar E. Iglesias     int trapnr, ret;
2520c227f099SAnthony Liguori     target_siginfo_t info;
2521b779e29eSEdgar E. Iglesias 
2522b779e29eSEdgar E. Iglesias     while (1) {
2523b779e29eSEdgar E. Iglesias         trapnr = cpu_mb_exec (env);
2524b779e29eSEdgar E. Iglesias         switch (trapnr) {
2525b779e29eSEdgar E. Iglesias         case 0xaa:
2526b779e29eSEdgar E. Iglesias             {
2527b779e29eSEdgar E. Iglesias                 info.si_signo = SIGSEGV;
2528b779e29eSEdgar E. Iglesias                 info.si_errno = 0;
2529b779e29eSEdgar E. Iglesias                 /* XXX: check env->error_code */
2530b779e29eSEdgar E. Iglesias                 info.si_code = TARGET_SEGV_MAPERR;
2531b779e29eSEdgar E. Iglesias                 info._sifields._sigfault._addr = 0;
2532b779e29eSEdgar E. Iglesias                 queue_signal(env, info.si_signo, &info);
2533b779e29eSEdgar E. Iglesias             }
2534b779e29eSEdgar E. Iglesias             break;
2535b779e29eSEdgar E. Iglesias 	case EXCP_INTERRUPT:
2536b779e29eSEdgar E. Iglesias 	  /* just indicate that signals should be handled asap */
2537b779e29eSEdgar E. Iglesias 	  break;
2538b779e29eSEdgar E. Iglesias         case EXCP_BREAK:
2539b779e29eSEdgar E. Iglesias             /* Return address is 4 bytes after the call.  */
2540b779e29eSEdgar E. Iglesias             env->regs[14] += 4;
2541d7dce494SEdgar E. Iglesias             env->sregs[SR_PC] = env->regs[14];
2542b779e29eSEdgar E. Iglesias             ret = do_syscall(env,
2543b779e29eSEdgar E. Iglesias                              env->regs[12],
2544b779e29eSEdgar E. Iglesias                              env->regs[5],
2545b779e29eSEdgar E. Iglesias                              env->regs[6],
2546b779e29eSEdgar E. Iglesias                              env->regs[7],
2547b779e29eSEdgar E. Iglesias                              env->regs[8],
2548b779e29eSEdgar E. Iglesias                              env->regs[9],
25495945cfcbSPeter Maydell                              env->regs[10],
25505945cfcbSPeter Maydell                              0, 0);
2551b779e29eSEdgar E. Iglesias             env->regs[3] = ret;
2552b779e29eSEdgar E. Iglesias             break;
2553b76da7e3SEdgar E. Iglesias         case EXCP_HW_EXCP:
2554b76da7e3SEdgar E. Iglesias             env->regs[17] = env->sregs[SR_PC] + 4;
2555b76da7e3SEdgar E. Iglesias             if (env->iflags & D_FLAG) {
2556b76da7e3SEdgar E. Iglesias                 env->sregs[SR_ESR] |= 1 << 12;
2557b76da7e3SEdgar E. Iglesias                 env->sregs[SR_PC] -= 4;
2558b76da7e3SEdgar E. Iglesias                 /* FIXME: if branch was immed, replay the imm as well.  */
2559b76da7e3SEdgar E. Iglesias             }
2560b76da7e3SEdgar E. Iglesias 
2561b76da7e3SEdgar E. Iglesias             env->iflags &= ~(IMM_FLAG | D_FLAG);
2562b76da7e3SEdgar E. Iglesias 
2563b76da7e3SEdgar E. Iglesias             switch (env->sregs[SR_ESR] & 31) {
256422a78d64SEdgar E. Iglesias                 case ESR_EC_DIVZERO:
256522a78d64SEdgar E. Iglesias                     info.si_signo = SIGFPE;
256622a78d64SEdgar E. Iglesias                     info.si_errno = 0;
256722a78d64SEdgar E. Iglesias                     info.si_code = TARGET_FPE_FLTDIV;
256822a78d64SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
256922a78d64SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
257022a78d64SEdgar E. Iglesias                     break;
2571b76da7e3SEdgar E. Iglesias                 case ESR_EC_FPU:
2572b76da7e3SEdgar E. Iglesias                     info.si_signo = SIGFPE;
2573b76da7e3SEdgar E. Iglesias                     info.si_errno = 0;
2574b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_IO) {
2575b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTINV;
2576b76da7e3SEdgar E. Iglesias                     }
2577b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_DZ) {
2578b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTDIV;
2579b76da7e3SEdgar E. Iglesias                     }
2580b76da7e3SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
2581b76da7e3SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2582b76da7e3SEdgar E. Iglesias                     break;
2583b76da7e3SEdgar E. Iglesias                 default:
2584b76da7e3SEdgar E. Iglesias                     printf ("Unhandled hw-exception: 0x%x\n",
25852e42d52dSEdgar E. Iglesias                             env->sregs[SR_ESR] & ESR_EC_MASK);
2586b76da7e3SEdgar E. Iglesias                     cpu_dump_state(env, stderr, fprintf, 0);
2587b76da7e3SEdgar E. Iglesias                     exit (1);
2588b76da7e3SEdgar E. Iglesias                     break;
2589b76da7e3SEdgar E. Iglesias             }
2590b76da7e3SEdgar E. Iglesias             break;
2591b779e29eSEdgar E. Iglesias         case EXCP_DEBUG:
2592b779e29eSEdgar E. Iglesias             {
2593b779e29eSEdgar E. Iglesias                 int sig;
2594b779e29eSEdgar E. Iglesias 
2595b779e29eSEdgar E. Iglesias                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2596b779e29eSEdgar E. Iglesias                 if (sig)
2597b779e29eSEdgar E. Iglesias                   {
2598b779e29eSEdgar E. Iglesias                     info.si_signo = sig;
2599b779e29eSEdgar E. Iglesias                     info.si_errno = 0;
2600b779e29eSEdgar E. Iglesias                     info.si_code = TARGET_TRAP_BRKPT;
2601b779e29eSEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2602b779e29eSEdgar E. Iglesias                   }
2603b779e29eSEdgar E. Iglesias             }
2604b779e29eSEdgar E. Iglesias             break;
2605b779e29eSEdgar E. Iglesias         default:
2606b779e29eSEdgar E. Iglesias             printf ("Unhandled trap: 0x%x\n", trapnr);
2607b779e29eSEdgar E. Iglesias             cpu_dump_state(env, stderr, fprintf, 0);
2608b779e29eSEdgar E. Iglesias             exit (1);
2609b779e29eSEdgar E. Iglesias         }
2610b779e29eSEdgar E. Iglesias         process_pending_signals (env);
2611b779e29eSEdgar E. Iglesias     }
2612b779e29eSEdgar E. Iglesias }
2613b779e29eSEdgar E. Iglesias #endif
2614b779e29eSEdgar E. Iglesias 
2615e6e5906bSpbrook #ifdef TARGET_M68K
2616e6e5906bSpbrook 
2617e6e5906bSpbrook void cpu_loop(CPUM68KState *env)
2618e6e5906bSpbrook {
2619e6e5906bSpbrook     int trapnr;
2620e6e5906bSpbrook     unsigned int n;
2621c227f099SAnthony Liguori     target_siginfo_t info;
2622e6e5906bSpbrook     TaskState *ts = env->opaque;
2623e6e5906bSpbrook 
2624e6e5906bSpbrook     for(;;) {
2625e6e5906bSpbrook         trapnr = cpu_m68k_exec(env);
2626e6e5906bSpbrook         switch(trapnr) {
2627e6e5906bSpbrook         case EXCP_ILLEGAL:
2628e6e5906bSpbrook             {
2629e6e5906bSpbrook                 if (ts->sim_syscalls) {
2630e6e5906bSpbrook                     uint16_t nr;
2631e6e5906bSpbrook                     nr = lduw(env->pc + 2);
2632e6e5906bSpbrook                     env->pc += 4;
2633e6e5906bSpbrook                     do_m68k_simcall(env, nr);
2634e6e5906bSpbrook                 } else {
2635e6e5906bSpbrook                     goto do_sigill;
2636e6e5906bSpbrook                 }
2637e6e5906bSpbrook             }
2638e6e5906bSpbrook             break;
2639a87295e8Spbrook         case EXCP_HALT_INSN:
2640e6e5906bSpbrook             /* Semihosing syscall.  */
2641a87295e8Spbrook             env->pc += 4;
2642e6e5906bSpbrook             do_m68k_semihosting(env, env->dregs[0]);
2643e6e5906bSpbrook             break;
2644e6e5906bSpbrook         case EXCP_LINEA:
2645e6e5906bSpbrook         case EXCP_LINEF:
2646e6e5906bSpbrook         case EXCP_UNSUPPORTED:
2647e6e5906bSpbrook         do_sigill:
2648e6e5906bSpbrook             info.si_signo = SIGILL;
2649e6e5906bSpbrook             info.si_errno = 0;
2650e6e5906bSpbrook             info.si_code = TARGET_ILL_ILLOPN;
2651e6e5906bSpbrook             info._sifields._sigfault._addr = env->pc;
2652624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2653e6e5906bSpbrook             break;
2654e6e5906bSpbrook         case EXCP_TRAP0:
2655e6e5906bSpbrook             {
2656e6e5906bSpbrook                 ts->sim_syscalls = 0;
2657e6e5906bSpbrook                 n = env->dregs[0];
2658e6e5906bSpbrook                 env->pc += 2;
2659e6e5906bSpbrook                 env->dregs[0] = do_syscall(env,
2660e6e5906bSpbrook                                           n,
2661e6e5906bSpbrook                                           env->dregs[1],
2662e6e5906bSpbrook                                           env->dregs[2],
2663e6e5906bSpbrook                                           env->dregs[3],
2664e6e5906bSpbrook                                           env->dregs[4],
2665e6e5906bSpbrook                                           env->dregs[5],
26665945cfcbSPeter Maydell                                           env->aregs[0],
26675945cfcbSPeter Maydell                                           0, 0);
2668e6e5906bSpbrook             }
2669e6e5906bSpbrook             break;
2670e6e5906bSpbrook         case EXCP_INTERRUPT:
2671e6e5906bSpbrook             /* just indicate that signals should be handled asap */
2672e6e5906bSpbrook             break;
2673e6e5906bSpbrook         case EXCP_ACCESS:
2674e6e5906bSpbrook             {
2675e6e5906bSpbrook                 info.si_signo = SIGSEGV;
2676e6e5906bSpbrook                 info.si_errno = 0;
2677e6e5906bSpbrook                 /* XXX: check env->error_code */
2678e6e5906bSpbrook                 info.si_code = TARGET_SEGV_MAPERR;
2679e6e5906bSpbrook                 info._sifields._sigfault._addr = env->mmu.ar;
2680624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
2681e6e5906bSpbrook             }
2682e6e5906bSpbrook             break;
2683e6e5906bSpbrook         case EXCP_DEBUG:
2684e6e5906bSpbrook             {
2685e6e5906bSpbrook                 int sig;
2686e6e5906bSpbrook 
2687e6e5906bSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2688e6e5906bSpbrook                 if (sig)
2689e6e5906bSpbrook                   {
2690e6e5906bSpbrook                     info.si_signo = sig;
2691e6e5906bSpbrook                     info.si_errno = 0;
2692e6e5906bSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2693624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2694e6e5906bSpbrook                   }
2695e6e5906bSpbrook             }
2696e6e5906bSpbrook             break;
2697e6e5906bSpbrook         default:
2698e6e5906bSpbrook             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2699e6e5906bSpbrook                     trapnr);
2700e6e5906bSpbrook             cpu_dump_state(env, stderr, fprintf, 0);
2701e6e5906bSpbrook             abort();
2702e6e5906bSpbrook         }
2703e6e5906bSpbrook         process_pending_signals(env);
2704e6e5906bSpbrook     }
2705e6e5906bSpbrook }
2706e6e5906bSpbrook #endif /* TARGET_M68K */
2707e6e5906bSpbrook 
27087a3148a9Sj_mayer #ifdef TARGET_ALPHA
27096910b8f6SRichard Henderson static void do_store_exclusive(CPUAlphaState *env, int reg, int quad)
27106910b8f6SRichard Henderson {
27116910b8f6SRichard Henderson     target_ulong addr, val, tmp;
27126910b8f6SRichard Henderson     target_siginfo_t info;
27136910b8f6SRichard Henderson     int ret = 0;
27146910b8f6SRichard Henderson 
27156910b8f6SRichard Henderson     addr = env->lock_addr;
27166910b8f6SRichard Henderson     tmp = env->lock_st_addr;
27176910b8f6SRichard Henderson     env->lock_addr = -1;
27186910b8f6SRichard Henderson     env->lock_st_addr = 0;
27196910b8f6SRichard Henderson 
27206910b8f6SRichard Henderson     start_exclusive();
27216910b8f6SRichard Henderson     mmap_lock();
27226910b8f6SRichard Henderson 
27236910b8f6SRichard Henderson     if (addr == tmp) {
27246910b8f6SRichard Henderson         if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
27256910b8f6SRichard Henderson             goto do_sigsegv;
27266910b8f6SRichard Henderson         }
27276910b8f6SRichard Henderson 
27286910b8f6SRichard Henderson         if (val == env->lock_value) {
27296910b8f6SRichard Henderson             tmp = env->ir[reg];
27306910b8f6SRichard Henderson             if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) {
27316910b8f6SRichard Henderson                 goto do_sigsegv;
27326910b8f6SRichard Henderson             }
27336910b8f6SRichard Henderson             ret = 1;
27346910b8f6SRichard Henderson         }
27356910b8f6SRichard Henderson     }
27366910b8f6SRichard Henderson     env->ir[reg] = ret;
27376910b8f6SRichard Henderson     env->pc += 4;
27386910b8f6SRichard Henderson 
27396910b8f6SRichard Henderson     mmap_unlock();
27406910b8f6SRichard Henderson     end_exclusive();
27416910b8f6SRichard Henderson     return;
27426910b8f6SRichard Henderson 
27436910b8f6SRichard Henderson  do_sigsegv:
27446910b8f6SRichard Henderson     mmap_unlock();
27456910b8f6SRichard Henderson     end_exclusive();
27466910b8f6SRichard Henderson 
27476910b8f6SRichard Henderson     info.si_signo = TARGET_SIGSEGV;
27486910b8f6SRichard Henderson     info.si_errno = 0;
27496910b8f6SRichard Henderson     info.si_code = TARGET_SEGV_MAPERR;
27506910b8f6SRichard Henderson     info._sifields._sigfault._addr = addr;
27516910b8f6SRichard Henderson     queue_signal(env, TARGET_SIGSEGV, &info);
27526910b8f6SRichard Henderson }
27536910b8f6SRichard Henderson 
275405390248SAndreas Färber void cpu_loop(CPUAlphaState *env)
27557a3148a9Sj_mayer {
2756e96efcfcSj_mayer     int trapnr;
2757c227f099SAnthony Liguori     target_siginfo_t info;
27586049f4f8SRichard Henderson     abi_long sysret;
27597a3148a9Sj_mayer 
27607a3148a9Sj_mayer     while (1) {
27617a3148a9Sj_mayer         trapnr = cpu_alpha_exec (env);
27627a3148a9Sj_mayer 
2763ac316ca4SRichard Henderson         /* All of the traps imply a transition through PALcode, which
2764ac316ca4SRichard Henderson            implies an REI instruction has been executed.  Which means
2765ac316ca4SRichard Henderson            that the intr_flag should be cleared.  */
2766ac316ca4SRichard Henderson         env->intr_flag = 0;
2767ac316ca4SRichard Henderson 
27687a3148a9Sj_mayer         switch (trapnr) {
27697a3148a9Sj_mayer         case EXCP_RESET:
27707a3148a9Sj_mayer             fprintf(stderr, "Reset requested. Exit\n");
27717a3148a9Sj_mayer             exit(1);
27727a3148a9Sj_mayer             break;
27737a3148a9Sj_mayer         case EXCP_MCHK:
27747a3148a9Sj_mayer             fprintf(stderr, "Machine check exception. Exit\n");
27757a3148a9Sj_mayer             exit(1);
27767a3148a9Sj_mayer             break;
277707b6c13bSRichard Henderson         case EXCP_SMP_INTERRUPT:
277807b6c13bSRichard Henderson         case EXCP_CLK_INTERRUPT:
277907b6c13bSRichard Henderson         case EXCP_DEV_INTERRUPT:
27807a3148a9Sj_mayer             fprintf(stderr, "External interrupt. Exit\n");
27817a3148a9Sj_mayer             exit(1);
27827a3148a9Sj_mayer             break;
278307b6c13bSRichard Henderson         case EXCP_MMFAULT:
27846910b8f6SRichard Henderson             env->lock_addr = -1;
27856049f4f8SRichard Henderson             info.si_signo = TARGET_SIGSEGV;
27866049f4f8SRichard Henderson             info.si_errno = 0;
2787129d8aa5SRichard Henderson             info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
27880be1d07cSRichard Henderson                             ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
2789129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
27906049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
27917a3148a9Sj_mayer             break;
27927a3148a9Sj_mayer         case EXCP_UNALIGN:
27936910b8f6SRichard Henderson             env->lock_addr = -1;
27946049f4f8SRichard Henderson             info.si_signo = TARGET_SIGBUS;
27956049f4f8SRichard Henderson             info.si_errno = 0;
27966049f4f8SRichard Henderson             info.si_code = TARGET_BUS_ADRALN;
2797129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
27986049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
27997a3148a9Sj_mayer             break;
28007a3148a9Sj_mayer         case EXCP_OPCDEC:
28016049f4f8SRichard Henderson         do_sigill:
28026910b8f6SRichard Henderson             env->lock_addr = -1;
28036049f4f8SRichard Henderson             info.si_signo = TARGET_SIGILL;
28046049f4f8SRichard Henderson             info.si_errno = 0;
28056049f4f8SRichard Henderson             info.si_code = TARGET_ILL_ILLOPC;
28066049f4f8SRichard Henderson             info._sifields._sigfault._addr = env->pc;
28076049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
28087a3148a9Sj_mayer             break;
280907b6c13bSRichard Henderson         case EXCP_ARITH:
281007b6c13bSRichard Henderson             env->lock_addr = -1;
281107b6c13bSRichard Henderson             info.si_signo = TARGET_SIGFPE;
281207b6c13bSRichard Henderson             info.si_errno = 0;
281307b6c13bSRichard Henderson             info.si_code = TARGET_FPE_FLTINV;
281407b6c13bSRichard Henderson             info._sifields._sigfault._addr = env->pc;
281507b6c13bSRichard Henderson             queue_signal(env, info.si_signo, &info);
281607b6c13bSRichard Henderson             break;
28177a3148a9Sj_mayer         case EXCP_FEN:
28186049f4f8SRichard Henderson             /* No-op.  Linux simply re-enables the FPU.  */
28197a3148a9Sj_mayer             break;
282007b6c13bSRichard Henderson         case EXCP_CALL_PAL:
28216910b8f6SRichard Henderson             env->lock_addr = -1;
282207b6c13bSRichard Henderson             switch (env->error_code) {
28236049f4f8SRichard Henderson             case 0x80:
28246049f4f8SRichard Henderson                 /* BPT */
28256049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
28266049f4f8SRichard Henderson                 info.si_errno = 0;
28276049f4f8SRichard Henderson                 info.si_code = TARGET_TRAP_BRKPT;
28286049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
28296049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
28306049f4f8SRichard Henderson                 break;
28316049f4f8SRichard Henderson             case 0x81:
28326049f4f8SRichard Henderson                 /* BUGCHK */
28336049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
28346049f4f8SRichard Henderson                 info.si_errno = 0;
28356049f4f8SRichard Henderson                 info.si_code = 0;
28366049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
28376049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
28386049f4f8SRichard Henderson                 break;
28396049f4f8SRichard Henderson             case 0x83:
28406049f4f8SRichard Henderson                 /* CALLSYS */
28416049f4f8SRichard Henderson                 trapnr = env->ir[IR_V0];
28426049f4f8SRichard Henderson                 sysret = do_syscall(env, trapnr,
28436049f4f8SRichard Henderson                                     env->ir[IR_A0], env->ir[IR_A1],
28446049f4f8SRichard Henderson                                     env->ir[IR_A2], env->ir[IR_A3],
28455945cfcbSPeter Maydell                                     env->ir[IR_A4], env->ir[IR_A5],
28465945cfcbSPeter Maydell                                     0, 0);
2847a5b3b13bSRichard Henderson                 if (trapnr == TARGET_NR_sigreturn
2848a5b3b13bSRichard Henderson                     || trapnr == TARGET_NR_rt_sigreturn) {
2849a5b3b13bSRichard Henderson                     break;
2850a5b3b13bSRichard Henderson                 }
2851a5b3b13bSRichard Henderson                 /* Syscall writes 0 to V0 to bypass error check, similar
28520e141977SRichard Henderson                    to how this is handled internal to Linux kernel.
28530e141977SRichard Henderson                    (Ab)use trapnr temporarily as boolean indicating error.  */
28540e141977SRichard Henderson                 trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
28550e141977SRichard Henderson                 env->ir[IR_V0] = (trapnr ? -sysret : sysret);
28560e141977SRichard Henderson                 env->ir[IR_A3] = trapnr;
28576049f4f8SRichard Henderson                 break;
28586049f4f8SRichard Henderson             case 0x86:
28596049f4f8SRichard Henderson                 /* IMB */
28606049f4f8SRichard Henderson                 /* ??? We can probably elide the code using page_unprotect
28616049f4f8SRichard Henderson                    that is checking for self-modifying code.  Instead we
28626049f4f8SRichard Henderson                    could simply call tb_flush here.  Until we work out the
28636049f4f8SRichard Henderson                    changes required to turn off the extra write protection,
28646049f4f8SRichard Henderson                    this can be a no-op.  */
28656049f4f8SRichard Henderson                 break;
28666049f4f8SRichard Henderson             case 0x9E:
28676049f4f8SRichard Henderson                 /* RDUNIQUE */
28686049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
28696049f4f8SRichard Henderson                 abort();
28706049f4f8SRichard Henderson             case 0x9F:
28716049f4f8SRichard Henderson                 /* WRUNIQUE */
28726049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
28736049f4f8SRichard Henderson                 abort();
28746049f4f8SRichard Henderson             case 0xAA:
28756049f4f8SRichard Henderson                 /* GENTRAP */
28766049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGFPE;
28776049f4f8SRichard Henderson                 switch (env->ir[IR_A0]) {
28786049f4f8SRichard Henderson                 case TARGET_GEN_INTOVF:
28796049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTOVF;
28806049f4f8SRichard Henderson                     break;
28816049f4f8SRichard Henderson                 case TARGET_GEN_INTDIV:
28826049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTDIV;
28836049f4f8SRichard Henderson                     break;
28846049f4f8SRichard Henderson                 case TARGET_GEN_FLTOVF:
28856049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTOVF;
28866049f4f8SRichard Henderson                     break;
28876049f4f8SRichard Henderson                 case TARGET_GEN_FLTUND:
28886049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTUND;
28896049f4f8SRichard Henderson                     break;
28906049f4f8SRichard Henderson                 case TARGET_GEN_FLTINV:
28916049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTINV;
28926049f4f8SRichard Henderson                     break;
28936049f4f8SRichard Henderson                 case TARGET_GEN_FLTINE:
28946049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTRES;
28956049f4f8SRichard Henderson                     break;
28966049f4f8SRichard Henderson                 case TARGET_GEN_ROPRAND:
28976049f4f8SRichard Henderson                     info.si_code = 0;
28986049f4f8SRichard Henderson                     break;
28996049f4f8SRichard Henderson                 default:
29006049f4f8SRichard Henderson                     info.si_signo = TARGET_SIGTRAP;
29016049f4f8SRichard Henderson                     info.si_code = 0;
29026049f4f8SRichard Henderson                     break;
29036049f4f8SRichard Henderson                 }
29046049f4f8SRichard Henderson                 info.si_errno = 0;
29056049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
29066049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
29076049f4f8SRichard Henderson                 break;
29086049f4f8SRichard Henderson             default:
29096049f4f8SRichard Henderson                 goto do_sigill;
29106049f4f8SRichard Henderson             }
29117a3148a9Sj_mayer             break;
29127a3148a9Sj_mayer         case EXCP_DEBUG:
29136049f4f8SRichard Henderson             info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
29146049f4f8SRichard Henderson             if (info.si_signo) {
29156910b8f6SRichard Henderson                 env->lock_addr = -1;
29167a3148a9Sj_mayer                 info.si_errno = 0;
29177a3148a9Sj_mayer                 info.si_code = TARGET_TRAP_BRKPT;
2918624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
29197a3148a9Sj_mayer             }
29207a3148a9Sj_mayer             break;
29216910b8f6SRichard Henderson         case EXCP_STL_C:
29226910b8f6SRichard Henderson         case EXCP_STQ_C:
29236910b8f6SRichard Henderson             do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
29246910b8f6SRichard Henderson             break;
2925d0f20495SRichard Henderson         case EXCP_INTERRUPT:
2926d0f20495SRichard Henderson             /* Just indicate that signals should be handled asap.  */
2927d0f20495SRichard Henderson             break;
29287a3148a9Sj_mayer         default:
29297a3148a9Sj_mayer             printf ("Unhandled trap: 0x%x\n", trapnr);
29307a3148a9Sj_mayer             cpu_dump_state(env, stderr, fprintf, 0);
29317a3148a9Sj_mayer             exit (1);
29327a3148a9Sj_mayer         }
29337a3148a9Sj_mayer         process_pending_signals (env);
29347a3148a9Sj_mayer     }
29357a3148a9Sj_mayer }
29367a3148a9Sj_mayer #endif /* TARGET_ALPHA */
29377a3148a9Sj_mayer 
2938a4c075f1SUlrich Hecht #ifdef TARGET_S390X
2939a4c075f1SUlrich Hecht void cpu_loop(CPUS390XState *env)
2940a4c075f1SUlrich Hecht {
2941a4c075f1SUlrich Hecht     int trapnr;
2942a4c075f1SUlrich Hecht     target_siginfo_t info;
2943a4c075f1SUlrich Hecht 
2944a4c075f1SUlrich Hecht     while (1) {
2945a4c075f1SUlrich Hecht         trapnr = cpu_s390x_exec (env);
2946a4c075f1SUlrich Hecht 
2947a4c075f1SUlrich Hecht         switch (trapnr) {
2948a4c075f1SUlrich Hecht         case EXCP_INTERRUPT:
2949a4c075f1SUlrich Hecht             /* just indicate that signals should be handled asap */
2950a4c075f1SUlrich Hecht             break;
2951a4c075f1SUlrich Hecht         case EXCP_DEBUG:
2952a4c075f1SUlrich Hecht             {
2953a4c075f1SUlrich Hecht                 int sig;
2954a4c075f1SUlrich Hecht 
2955a4c075f1SUlrich Hecht                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2956a4c075f1SUlrich Hecht                 if (sig) {
2957a4c075f1SUlrich Hecht                     info.si_signo = sig;
2958a4c075f1SUlrich Hecht                     info.si_errno = 0;
2959a4c075f1SUlrich Hecht                     info.si_code = TARGET_TRAP_BRKPT;
2960a4c075f1SUlrich Hecht                     queue_signal(env, info.si_signo, &info);
2961a4c075f1SUlrich Hecht                 }
2962a4c075f1SUlrich Hecht             }
2963a4c075f1SUlrich Hecht             break;
2964a4c075f1SUlrich Hecht         case EXCP_SVC:
2965a4c075f1SUlrich Hecht             {
2966a4c075f1SUlrich Hecht                 int n = env->int_svc_code;
2967a4c075f1SUlrich Hecht                 if (!n) {
2968a4c075f1SUlrich Hecht                     /* syscalls > 255 */
2969a4c075f1SUlrich Hecht                     n = env->regs[1];
2970a4c075f1SUlrich Hecht                 }
2971a4c075f1SUlrich Hecht                 env->psw.addr += env->int_svc_ilc;
2972a4c075f1SUlrich Hecht                 env->regs[2] = do_syscall(env, n,
2973a4c075f1SUlrich Hecht                            env->regs[2],
2974a4c075f1SUlrich Hecht                            env->regs[3],
2975a4c075f1SUlrich Hecht                            env->regs[4],
2976a4c075f1SUlrich Hecht                            env->regs[5],
2977a4c075f1SUlrich Hecht                            env->regs[6],
29785945cfcbSPeter Maydell                            env->regs[7],
29795945cfcbSPeter Maydell                            0, 0);
2980a4c075f1SUlrich Hecht             }
2981a4c075f1SUlrich Hecht             break;
2982a4c075f1SUlrich Hecht         case EXCP_ADDR:
2983a4c075f1SUlrich Hecht             {
2984a4c075f1SUlrich Hecht                 info.si_signo = SIGSEGV;
2985a4c075f1SUlrich Hecht                 info.si_errno = 0;
2986a4c075f1SUlrich Hecht                 /* XXX: check env->error_code */
2987a4c075f1SUlrich Hecht                 info.si_code = TARGET_SEGV_MAPERR;
2988a4c075f1SUlrich Hecht                 info._sifields._sigfault._addr = env->__excp_addr;
2989a4c075f1SUlrich Hecht                 queue_signal(env, info.si_signo, &info);
2990a4c075f1SUlrich Hecht             }
2991a4c075f1SUlrich Hecht             break;
2992a4c075f1SUlrich Hecht         case EXCP_SPEC:
2993a4c075f1SUlrich Hecht             {
2994a4c075f1SUlrich Hecht                 fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4));
2995a4c075f1SUlrich Hecht                 info.si_signo = SIGILL;
2996a4c075f1SUlrich Hecht                 info.si_errno = 0;
2997a4c075f1SUlrich Hecht                 info.si_code = TARGET_ILL_ILLOPC;
2998a4c075f1SUlrich Hecht                 info._sifields._sigfault._addr = env->__excp_addr;
2999a4c075f1SUlrich Hecht                 queue_signal(env, info.si_signo, &info);
3000a4c075f1SUlrich Hecht             }
3001a4c075f1SUlrich Hecht             break;
3002a4c075f1SUlrich Hecht         default:
3003a4c075f1SUlrich Hecht             printf ("Unhandled trap: 0x%x\n", trapnr);
3004a4c075f1SUlrich Hecht             cpu_dump_state(env, stderr, fprintf, 0);
3005a4c075f1SUlrich Hecht             exit (1);
3006a4c075f1SUlrich Hecht         }
3007a4c075f1SUlrich Hecht         process_pending_signals (env);
3008a4c075f1SUlrich Hecht     }
3009a4c075f1SUlrich Hecht }
3010a4c075f1SUlrich Hecht 
3011a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
3012a4c075f1SUlrich Hecht 
30139349b4f9SAndreas Färber THREAD CPUArchState *thread_env;
301459faf6d6Sbellard 
3015edf8e2afSMika Westerberg void task_settid(TaskState *ts)
3016edf8e2afSMika Westerberg {
3017edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
30182f7bb878SJuan Quintela #ifdef CONFIG_USE_NPTL
3019edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
3020edf8e2afSMika Westerberg #else
3021edf8e2afSMika Westerberg         /* when no threads are used, tid becomes pid */
3022edf8e2afSMika Westerberg         ts->ts_tid = getpid();
3023edf8e2afSMika Westerberg #endif
3024edf8e2afSMika Westerberg     }
3025edf8e2afSMika Westerberg }
3026edf8e2afSMika Westerberg 
3027edf8e2afSMika Westerberg void stop_all_tasks(void)
3028edf8e2afSMika Westerberg {
3029edf8e2afSMika Westerberg     /*
3030edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
3031edf8e2afSMika Westerberg      * handles thread stopping correctly.
3032edf8e2afSMika Westerberg      */
3033edf8e2afSMika Westerberg     start_exclusive();
3034edf8e2afSMika Westerberg }
3035edf8e2afSMika Westerberg 
3036c3a92833Spbrook /* Assumes contents are already zeroed.  */
3037624f7979Spbrook void init_task_state(TaskState *ts)
3038624f7979Spbrook {
3039624f7979Spbrook     int i;
3040624f7979Spbrook 
3041624f7979Spbrook     ts->used = 1;
3042624f7979Spbrook     ts->first_free = ts->sigqueue_table;
3043624f7979Spbrook     for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
3044624f7979Spbrook         ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
3045624f7979Spbrook     }
3046624f7979Spbrook     ts->sigqueue_table[i].next = NULL;
3047624f7979Spbrook }
30489de5e440Sbellard 
3049fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
3050fc9c5412SJohannes Schauer {
3051fc9c5412SJohannes Schauer     usage();
3052fc9c5412SJohannes Schauer }
3053fc9c5412SJohannes Schauer 
3054fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
3055fc9c5412SJohannes Schauer {
3056fc9c5412SJohannes Schauer     int mask;
3057fc9c5412SJohannes Schauer     const CPULogItem *item;
3058fc9c5412SJohannes Schauer 
3059fc9c5412SJohannes Schauer     mask = cpu_str_to_log_mask(arg);
3060fc9c5412SJohannes Schauer     if (!mask) {
3061fc9c5412SJohannes Schauer         printf("Log items (comma separated):\n");
3062fc9c5412SJohannes Schauer         for (item = cpu_log_items; item->mask != 0; item++) {
3063fc9c5412SJohannes Schauer             printf("%-10s %s\n", item->name, item->help);
3064fc9c5412SJohannes Schauer         }
3065fc9c5412SJohannes Schauer         exit(1);
3066fc9c5412SJohannes Schauer     }
3067fc9c5412SJohannes Schauer     cpu_set_log(mask);
3068fc9c5412SJohannes Schauer }
3069fc9c5412SJohannes Schauer 
307050171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
307150171d42S陳韋任 {
307250171d42S陳韋任     cpu_set_log_filename(arg);
307350171d42S陳韋任 }
307450171d42S陳韋任 
3075fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
3076fc9c5412SJohannes Schauer {
3077fc9c5412SJohannes Schauer     char *r, *p, *token;
3078fc9c5412SJohannes Schauer     r = p = strdup(arg);
3079fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
3080fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
3081fc9c5412SJohannes Schauer             usage();
3082fc9c5412SJohannes Schauer         }
3083fc9c5412SJohannes Schauer     }
3084fc9c5412SJohannes Schauer     free(r);
3085fc9c5412SJohannes Schauer }
3086fc9c5412SJohannes Schauer 
3087fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
3088fc9c5412SJohannes Schauer {
3089fc9c5412SJohannes Schauer     char *r, *p, *token;
3090fc9c5412SJohannes Schauer     r = p = strdup(arg);
3091fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
3092fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
3093fc9c5412SJohannes Schauer             usage();
3094fc9c5412SJohannes Schauer         }
3095fc9c5412SJohannes Schauer     }
3096fc9c5412SJohannes Schauer     free(r);
3097fc9c5412SJohannes Schauer }
3098fc9c5412SJohannes Schauer 
3099fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
3100fc9c5412SJohannes Schauer {
3101fc9c5412SJohannes Schauer     argv0 = strdup(arg);
3102fc9c5412SJohannes Schauer }
3103fc9c5412SJohannes Schauer 
3104fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
3105fc9c5412SJohannes Schauer {
3106fc9c5412SJohannes Schauer     char *p;
3107fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
3108fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
3109fc9c5412SJohannes Schauer         usage();
3110fc9c5412SJohannes Schauer     }
3111fc9c5412SJohannes Schauer 
3112fc9c5412SJohannes Schauer     if (*p == 'M') {
3113fc9c5412SJohannes Schauer         guest_stack_size *= 1024 * 1024;
3114fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
3115fc9c5412SJohannes Schauer         guest_stack_size *= 1024;
3116fc9c5412SJohannes Schauer     }
3117fc9c5412SJohannes Schauer }
3118fc9c5412SJohannes Schauer 
3119fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
3120fc9c5412SJohannes Schauer {
3121fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
3122fc9c5412SJohannes Schauer }
3123fc9c5412SJohannes Schauer 
3124fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
3125fc9c5412SJohannes Schauer {
3126fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
3127fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
3128fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
3129fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
3130fc9c5412SJohannes Schauer         exit(1);
3131fc9c5412SJohannes Schauer     }
3132fc9c5412SJohannes Schauer }
3133fc9c5412SJohannes Schauer 
3134fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
3135fc9c5412SJohannes Schauer {
3136fc9c5412SJohannes Schauer     gdbstub_port = atoi(arg);
3137fc9c5412SJohannes Schauer }
3138fc9c5412SJohannes Schauer 
3139fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
3140fc9c5412SJohannes Schauer {
3141fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
3142fc9c5412SJohannes Schauer }
3143fc9c5412SJohannes Schauer 
3144fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
3145fc9c5412SJohannes Schauer {
3146fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
3147c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
3148fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
3149e916cbf8SPeter Maydell #if defined(cpu_list)
3150e916cbf8SPeter Maydell         cpu_list(stdout, &fprintf);
3151fc9c5412SJohannes Schauer #endif
3152fc9c5412SJohannes Schauer         exit(1);
3153fc9c5412SJohannes Schauer     }
3154fc9c5412SJohannes Schauer }
3155fc9c5412SJohannes Schauer 
3156fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE)
3157fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
3158fc9c5412SJohannes Schauer {
3159fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
3160fc9c5412SJohannes Schauer     have_guest_base = 1;
3161fc9c5412SJohannes Schauer }
3162fc9c5412SJohannes Schauer 
3163fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
3164fc9c5412SJohannes Schauer {
3165fc9c5412SJohannes Schauer     char *p;
3166fc9c5412SJohannes Schauer     int shift = 0;
3167fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
3168fc9c5412SJohannes Schauer     switch (*p) {
3169fc9c5412SJohannes Schauer     case 'k':
3170fc9c5412SJohannes Schauer     case 'K':
3171fc9c5412SJohannes Schauer         shift = 10;
3172fc9c5412SJohannes Schauer         break;
3173fc9c5412SJohannes Schauer     case 'M':
3174fc9c5412SJohannes Schauer         shift = 20;
3175fc9c5412SJohannes Schauer         break;
3176fc9c5412SJohannes Schauer     case 'G':
3177fc9c5412SJohannes Schauer         shift = 30;
3178fc9c5412SJohannes Schauer         break;
3179fc9c5412SJohannes Schauer     }
3180fc9c5412SJohannes Schauer     if (shift) {
3181fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
3182fc9c5412SJohannes Schauer         p++;
3183fc9c5412SJohannes Schauer         reserved_va <<= shift;
3184fc9c5412SJohannes Schauer         if (((reserved_va >> shift) != unshifted)
3185fc9c5412SJohannes Schauer #if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
3186fc9c5412SJohannes Schauer             || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
3187fc9c5412SJohannes Schauer #endif
3188fc9c5412SJohannes Schauer             ) {
3189fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
3190fc9c5412SJohannes Schauer             exit(1);
3191fc9c5412SJohannes Schauer         }
3192fc9c5412SJohannes Schauer     }
3193fc9c5412SJohannes Schauer     if (*p) {
3194fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
3195fc9c5412SJohannes Schauer         exit(1);
3196fc9c5412SJohannes Schauer     }
3197fc9c5412SJohannes Schauer }
3198fc9c5412SJohannes Schauer #endif
3199fc9c5412SJohannes Schauer 
3200fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
3201fc9c5412SJohannes Schauer {
3202fc9c5412SJohannes Schauer     singlestep = 1;
3203fc9c5412SJohannes Schauer }
3204fc9c5412SJohannes Schauer 
3205fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
3206fc9c5412SJohannes Schauer {
3207fc9c5412SJohannes Schauer     do_strace = 1;
3208fc9c5412SJohannes Schauer }
3209fc9c5412SJohannes Schauer 
3210fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
3211fc9c5412SJohannes Schauer {
3212fc9c5412SJohannes Schauer     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
3213fc9c5412SJohannes Schauer            ", Copyright (c) 2003-2008 Fabrice Bellard\n");
32141386d4c0SPeter Maydell     exit(0);
3215fc9c5412SJohannes Schauer }
3216fc9c5412SJohannes Schauer 
3217fc9c5412SJohannes Schauer struct qemu_argument {
3218fc9c5412SJohannes Schauer     const char *argv;
3219fc9c5412SJohannes Schauer     const char *env;
3220fc9c5412SJohannes Schauer     bool has_arg;
3221fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
3222fc9c5412SJohannes Schauer     const char *example;
3223fc9c5412SJohannes Schauer     const char *help;
3224fc9c5412SJohannes Schauer };
3225fc9c5412SJohannes Schauer 
322642644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
3227fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
3228fc9c5412SJohannes Schauer      "",           "print this help"},
3229fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
3230fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
3231fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
3232fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
3233fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
3234fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
3235fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
3236c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
3237fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
3238fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
3239fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
3240fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
3241fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
3242fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
3243fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
3244fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
3245fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE)
3246fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
3247fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
3248fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
3249fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
3250fc9c5412SJohannes Schauer #endif
3251fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
3252fc9c5412SJohannes Schauer      "options",    "activate log"},
325350171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
325450171d42S陳韋任      "logfile",     "override default logfile location"},
3255fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
3256fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
3257fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
3258fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
3259fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
3260fc9c5412SJohannes Schauer      "",           "log system calls"},
3261fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
32621386d4c0SPeter Maydell      "",           "display version information and exit"},
3263fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
3264fc9c5412SJohannes Schauer };
3265fc9c5412SJohannes Schauer 
3266fc9c5412SJohannes Schauer static void usage(void)
3267fc9c5412SJohannes Schauer {
326842644ceeSJim Meyering     const struct qemu_argument *arginfo;
3269fc9c5412SJohannes Schauer     int maxarglen;
3270fc9c5412SJohannes Schauer     int maxenvlen;
3271fc9c5412SJohannes Schauer 
3272fc9c5412SJohannes Schauer     printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
3273fc9c5412SJohannes Schauer            "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
3274fc9c5412SJohannes Schauer            "\n"
3275fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
3276fc9c5412SJohannes Schauer            "\n");
3277fc9c5412SJohannes Schauer 
3278fc9c5412SJohannes Schauer     maxarglen = maxenvlen = 0;
3279fc9c5412SJohannes Schauer 
3280fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3281fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
3282fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
3283fc9c5412SJohannes Schauer         }
3284fc9c5412SJohannes Schauer         if (strlen(arginfo->argv) > maxarglen) {
3285fc9c5412SJohannes Schauer             maxarglen = strlen(arginfo->argv);
3286fc9c5412SJohannes Schauer         }
3287fc9c5412SJohannes Schauer     }
3288fc9c5412SJohannes Schauer 
3289fc9c5412SJohannes Schauer     printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
3290fc9c5412SJohannes Schauer             maxenvlen+1, "Env-variable");
3291fc9c5412SJohannes Schauer 
3292fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3293fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
3294fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
3295fc9c5412SJohannes Schauer                     (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
3296fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env, arginfo->help);
3297fc9c5412SJohannes Schauer         } else {
3298fc9c5412SJohannes Schauer             printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
3299fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
3300fc9c5412SJohannes Schauer                     arginfo->help);
3301fc9c5412SJohannes Schauer         }
3302fc9c5412SJohannes Schauer     }
3303fc9c5412SJohannes Schauer 
3304fc9c5412SJohannes Schauer     printf("\n"
3305fc9c5412SJohannes Schauer            "Defaults:\n"
3306fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
3307fc9c5412SJohannes Schauer            "QEMU_STACK_SIZE = %ld byte\n"
3308fc9c5412SJohannes Schauer            "QEMU_LOG        = %s\n",
3309fc9c5412SJohannes Schauer            interp_prefix,
3310fc9c5412SJohannes Schauer            guest_stack_size,
3311fc9c5412SJohannes Schauer            DEBUG_LOGFILE);
3312fc9c5412SJohannes Schauer 
3313fc9c5412SJohannes Schauer     printf("\n"
3314fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
3315fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
3316fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
3317fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
3318fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
3319fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
3320fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
3321fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
3322fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
3323fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
3324fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
3325fc9c5412SJohannes Schauer            "the last change will stay in effect.\n");
3326fc9c5412SJohannes Schauer 
3327fc9c5412SJohannes Schauer     exit(1);
3328fc9c5412SJohannes Schauer }
3329fc9c5412SJohannes Schauer 
3330fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
3331fc9c5412SJohannes Schauer {
3332fc9c5412SJohannes Schauer     const char *r;
3333fc9c5412SJohannes Schauer     int optind;
333442644ceeSJim Meyering     const struct qemu_argument *arginfo;
3335fc9c5412SJohannes Schauer 
3336fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3337fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
3338fc9c5412SJohannes Schauer             continue;
3339fc9c5412SJohannes Schauer         }
3340fc9c5412SJohannes Schauer 
3341fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
3342fc9c5412SJohannes Schauer         if (r != NULL) {
3343fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
3344fc9c5412SJohannes Schauer         }
3345fc9c5412SJohannes Schauer     }
3346fc9c5412SJohannes Schauer 
3347fc9c5412SJohannes Schauer     optind = 1;
3348fc9c5412SJohannes Schauer     for (;;) {
3349fc9c5412SJohannes Schauer         if (optind >= argc) {
3350fc9c5412SJohannes Schauer             break;
3351fc9c5412SJohannes Schauer         }
3352fc9c5412SJohannes Schauer         r = argv[optind];
3353fc9c5412SJohannes Schauer         if (r[0] != '-') {
3354fc9c5412SJohannes Schauer             break;
3355fc9c5412SJohannes Schauer         }
3356fc9c5412SJohannes Schauer         optind++;
3357fc9c5412SJohannes Schauer         r++;
3358fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
3359fc9c5412SJohannes Schauer             break;
3360fc9c5412SJohannes Schauer         }
3361fc9c5412SJohannes Schauer 
3362fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3363fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
33641386d4c0SPeter Maydell                 if (arginfo->has_arg) {
3365fc9c5412SJohannes Schauer                     if (optind >= argc) {
3366fc9c5412SJohannes Schauer                         usage();
3367fc9c5412SJohannes Schauer                     }
3368fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
3369fc9c5412SJohannes Schauer                     optind++;
33701386d4c0SPeter Maydell                 } else {
33711386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
3372fc9c5412SJohannes Schauer                 }
3373fc9c5412SJohannes Schauer                 break;
3374fc9c5412SJohannes Schauer             }
3375fc9c5412SJohannes Schauer         }
3376fc9c5412SJohannes Schauer 
3377fc9c5412SJohannes Schauer         /* no option matched the current argv */
3378fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
3379fc9c5412SJohannes Schauer             usage();
3380fc9c5412SJohannes Schauer         }
3381fc9c5412SJohannes Schauer     }
3382fc9c5412SJohannes Schauer 
3383fc9c5412SJohannes Schauer     if (optind >= argc) {
3384fc9c5412SJohannes Schauer         usage();
3385fc9c5412SJohannes Schauer     }
3386fc9c5412SJohannes Schauer 
3387fc9c5412SJohannes Schauer     filename = argv[optind];
3388fc9c5412SJohannes Schauer     exec_path = argv[optind];
3389fc9c5412SJohannes Schauer 
3390fc9c5412SJohannes Schauer     return optind;
3391fc9c5412SJohannes Schauer }
3392fc9c5412SJohannes Schauer 
3393902b3d5cSmalc int main(int argc, char **argv, char **envp)
339431e31b8aSbellard {
3395c235d738SMatthew Fernandez     const char *log_file = DEBUG_LOGFILE;
339601ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
339731e31b8aSbellard     struct image_info info1, *info = &info1;
3398edf8e2afSMika Westerberg     struct linux_binprm bprm;
339948e15fc2SNathan Froyd     TaskState *ts;
34009349b4f9SAndreas Färber     CPUArchState *env;
3401586314f2Sbellard     int optind;
340204a6dfebSaurel32     char **target_environ, **wrk;
34037d8cec95Saurel32     char **target_argv;
34047d8cec95Saurel32     int target_argc;
34057d8cec95Saurel32     int i;
3406fd4d81ddSArnaud Patard     int ret;
340731e31b8aSbellard 
3408ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
3409ce008c1fSAndreas Färber 
3410902b3d5cSmalc     qemu_cache_utils_init(envp);
3411902b3d5cSmalc 
341204a6dfebSaurel32     if ((envlist = envlist_create()) == NULL) {
341304a6dfebSaurel32         (void) fprintf(stderr, "Unable to allocate envlist\n");
341404a6dfebSaurel32         exit(1);
341504a6dfebSaurel32     }
341604a6dfebSaurel32 
341704a6dfebSaurel32     /* add current environment into the list */
341804a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
341904a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
342004a6dfebSaurel32     }
342104a6dfebSaurel32 
3422703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
3423703e0e89SRichard Henderson        then we can do little else besides use the default.  */
3424703e0e89SRichard Henderson     {
3425703e0e89SRichard Henderson         struct rlimit lim;
3426703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
342781bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
342881bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur == (target_long)lim.rlim_cur) {
3429703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
3430703e0e89SRichard Henderson         }
3431703e0e89SRichard Henderson     }
3432703e0e89SRichard Henderson 
3433b1f9be31Sj_mayer     cpu_model = NULL;
3434b5ec5ce0Sjohn cooper #if defined(cpudef_setup)
3435b5ec5ce0Sjohn cooper     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
3436b5ec5ce0Sjohn cooper #endif
3437b5ec5ce0Sjohn cooper 
3438c235d738SMatthew Fernandez     /* init debug */
3439c235d738SMatthew Fernandez     cpu_set_log_filename(log_file);
3440fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
34414b5dfd82SPeter Maydell 
344231e31b8aSbellard     /* Zero out regs */
344301ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
344431e31b8aSbellard 
344531e31b8aSbellard     /* Zero out image_info */
344631e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
344731e31b8aSbellard 
3448edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
3449edf8e2afSMika Westerberg 
345074cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
345174cd30b8Sbellard     init_paths(interp_prefix);
345274cd30b8Sbellard 
345346027c07Sbellard     if (cpu_model == NULL) {
3454aaed909aSbellard #if defined(TARGET_I386)
345546027c07Sbellard #ifdef TARGET_X86_64
345646027c07Sbellard         cpu_model = "qemu64";
345746027c07Sbellard #else
345846027c07Sbellard         cpu_model = "qemu32";
345946027c07Sbellard #endif
3460aaed909aSbellard #elif defined(TARGET_ARM)
3461088ab16cSpbrook         cpu_model = "any";
3462d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
3463d2fbca94SGuan Xuetao         cpu_model = "any";
3464aaed909aSbellard #elif defined(TARGET_M68K)
3465aaed909aSbellard         cpu_model = "any";
3466aaed909aSbellard #elif defined(TARGET_SPARC)
3467aaed909aSbellard #ifdef TARGET_SPARC64
3468aaed909aSbellard         cpu_model = "TI UltraSparc II";
3469aaed909aSbellard #else
3470aaed909aSbellard         cpu_model = "Fujitsu MB86904";
347146027c07Sbellard #endif
3472aaed909aSbellard #elif defined(TARGET_MIPS)
3473aaed909aSbellard #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
3474aaed909aSbellard         cpu_model = "20Kc";
3475aaed909aSbellard #else
3476aaed909aSbellard         cpu_model = "24Kf";
3477aaed909aSbellard #endif
3478d962783eSJia Liu #elif defined TARGET_OPENRISC
3479d962783eSJia Liu         cpu_model = "or1200";
3480aaed909aSbellard #elif defined(TARGET_PPC)
34817ded4f52Sbellard #ifdef TARGET_PPC64
3482f7177937SAurelien Jarno         cpu_model = "970fx";
34837ded4f52Sbellard #else
3484aaed909aSbellard         cpu_model = "750";
34857ded4f52Sbellard #endif
3486aaed909aSbellard #else
3487aaed909aSbellard         cpu_model = "any";
3488aaed909aSbellard #endif
3489aaed909aSbellard     }
3490d5ab9713SJan Kiszka     tcg_exec_init(0);
3491d5ab9713SJan Kiszka     cpu_exec_init_all();
349283fb7adfSbellard     /* NOTE: we need to init the CPU at this stage to get
349383fb7adfSbellard        qemu_host_page_size */
3494aaed909aSbellard     env = cpu_init(cpu_model);
3495aaed909aSbellard     if (!env) {
3496aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
3497aaed909aSbellard         exit(1);
3498aaed909aSbellard     }
3499b55a37c9SBlue Swirl #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
3500ff18b762SAndreas Färber     cpu_reset(ENV_GET_CPU(env));
3501b55a37c9SBlue Swirl #endif
3502b55a37c9SBlue Swirl 
3503d5975363Spbrook     thread_env = env;
350454936004Sbellard 
3505b92c47c1Sths     if (getenv("QEMU_STRACE")) {
3506b92c47c1Sths         do_strace = 1;
3507b92c47c1Sths     }
3508b92c47c1Sths 
350904a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
351004a6dfebSaurel32     envlist_free(envlist);
3511b12b6a18Sths 
3512379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
3513379f6698SPaul Brook     /*
3514379f6698SPaul Brook      * Now that page sizes are configured in cpu_init() we can do
3515379f6698SPaul Brook      * proper page alignment for guest_base.
3516379f6698SPaul Brook      */
3517379f6698SPaul Brook     guest_base = HOST_PAGE_ALIGN(guest_base);
351868a1c816SPaul Brook 
351997cc7560SDr. David Alan Gilbert     if (reserved_va || have_guest_base) {
3520806d1021SMeador Inge         guest_base = init_guest_space(guest_base, reserved_va, 0,
3521806d1021SMeador Inge                                       have_guest_base);
3522806d1021SMeador Inge         if (guest_base == (unsigned long)-1) {
3523097b8cb8SPeter Maydell             fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address "
3524097b8cb8SPeter Maydell                     "space for use as guest address space (check your virtual "
3525097b8cb8SPeter Maydell                     "memory ulimit setting or reserve less using -R option)\n",
3526097b8cb8SPeter Maydell                     reserved_va);
352797cc7560SDr. David Alan Gilbert             exit(1);
352897cc7560SDr. David Alan Gilbert         }
3529806d1021SMeador Inge 
3530806d1021SMeador Inge         if (reserved_va) {
3531806d1021SMeador Inge             mmap_next_start = reserved_va;
3532806d1021SMeador Inge         }
353397cc7560SDr. David Alan Gilbert     }
353414f24e14SRichard Henderson #endif /* CONFIG_USE_GUEST_BASE */
3535379f6698SPaul Brook 
3536379f6698SPaul Brook     /*
3537379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
3538379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
353914f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
3540379f6698SPaul Brook      */
354114f24e14SRichard Henderson     {
3542379f6698SPaul Brook         FILE *fp;
3543379f6698SPaul Brook 
3544379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
3545379f6698SPaul Brook             unsigned long tmp;
3546379f6698SPaul Brook             if (fscanf(fp, "%lu", &tmp) == 1) {
3547379f6698SPaul Brook                 mmap_min_addr = tmp;
3548379f6698SPaul Brook                 qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
3549379f6698SPaul Brook             }
3550379f6698SPaul Brook             fclose(fp);
3551379f6698SPaul Brook         }
3552379f6698SPaul Brook     }
3553379f6698SPaul Brook 
35547d8cec95Saurel32     /*
35557d8cec95Saurel32      * Prepare copy of argv vector for target.
35567d8cec95Saurel32      */
35577d8cec95Saurel32     target_argc = argc - optind;
35587d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
35597d8cec95Saurel32     if (target_argv == NULL) {
35607d8cec95Saurel32 	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
35617d8cec95Saurel32 	exit(1);
35627d8cec95Saurel32     }
35637d8cec95Saurel32 
35647d8cec95Saurel32     /*
35657d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
35667d8cec95Saurel32      * argv[0] pointer with the given one.
35677d8cec95Saurel32      */
35687d8cec95Saurel32     i = 0;
35697d8cec95Saurel32     if (argv0 != NULL) {
35707d8cec95Saurel32         target_argv[i++] = strdup(argv0);
35717d8cec95Saurel32     }
35727d8cec95Saurel32     for (; i < target_argc; i++) {
35737d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
35747d8cec95Saurel32     }
35757d8cec95Saurel32     target_argv[target_argc] = NULL;
35767d8cec95Saurel32 
35777267c094SAnthony Liguori     ts = g_malloc0 (sizeof(TaskState));
3578edf8e2afSMika Westerberg     init_task_state(ts);
3579edf8e2afSMika Westerberg     /* build Task State */
3580edf8e2afSMika Westerberg     ts->info = info;
3581edf8e2afSMika Westerberg     ts->bprm = &bprm;
3582edf8e2afSMika Westerberg     env->opaque = ts;
3583edf8e2afSMika Westerberg     task_settid(ts);
3584edf8e2afSMika Westerberg 
3585fd4d81ddSArnaud Patard     ret = loader_exec(filename, target_argv, target_environ, regs,
3586fd4d81ddSArnaud Patard         info, &bprm);
3587fd4d81ddSArnaud Patard     if (ret != 0) {
3588885c1d10SPeter Maydell         printf("Error while loading %s: %s\n", filename, strerror(-ret));
358974cd30b8Sbellard         _exit(1);
359031e31b8aSbellard     }
359131e31b8aSbellard 
3592b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
3593b12b6a18Sths         free(*wrk);
3594b12b6a18Sths     }
3595b12b6a18Sths 
3596b12b6a18Sths     free(target_environ);
3597b12b6a18Sths 
35982e77eac6Sblueswir1     if (qemu_log_enabled()) {
3599379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
3600379f6698SPaul Brook         qemu_log("guest_base  0x%lx\n", guest_base);
3601379f6698SPaul Brook #endif
360293fcfe39Saliguori         log_page_dump();
360354936004Sbellard 
360493fcfe39Saliguori         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
360593fcfe39Saliguori         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
360693fcfe39Saliguori         qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
36073d177870Sj_mayer                  info->start_code);
360893fcfe39Saliguori         qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
36093d177870Sj_mayer                  info->start_data);
361093fcfe39Saliguori         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
361193fcfe39Saliguori         qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
36123d177870Sj_mayer                  info->start_stack);
361393fcfe39Saliguori         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
361493fcfe39Saliguori         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
36152e77eac6Sblueswir1     }
361631e31b8aSbellard 
361753a5960aSpbrook     target_set_brk(info->brk);
361831e31b8aSbellard     syscall_init();
361966fb9763Sbellard     signal_init();
362031e31b8aSbellard 
36219002ec79SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE)
36229002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
36239002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
36249002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
36259002ec79SRichard Henderson     tcg_prologue_init(&tcg_ctx);
36269002ec79SRichard Henderson #endif
36279002ec79SRichard Henderson 
3628b346ff46Sbellard #if defined(TARGET_I386)
36292e255c6bSbellard     cpu_x86_set_cpl(env, 3);
36302e255c6bSbellard 
36313802ce26Sbellard     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
36321bde465eSbellard     env->hflags |= HF_PE_MASK;
36331bde465eSbellard     if (env->cpuid_features & CPUID_SSE) {
36341bde465eSbellard         env->cr[4] |= CR4_OSFXSR_MASK;
36351bde465eSbellard         env->hflags |= HF_OSFXSR_MASK;
36361bde465eSbellard     }
3637d2fd1af7Sbellard #ifndef TARGET_ABI32
36384dbc422bSbellard     /* enable 64 bit mode if possible */
36394dbc422bSbellard     if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
36404dbc422bSbellard         fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
36414dbc422bSbellard         exit(1);
36424dbc422bSbellard     }
3643d2fd1af7Sbellard     env->cr[4] |= CR4_PAE_MASK;
36444dbc422bSbellard     env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
3645d2fd1af7Sbellard     env->hflags |= HF_LMA_MASK;
3646d2fd1af7Sbellard #endif
36473802ce26Sbellard 
3648415e561fSbellard     /* flags setup : we activate the IRQs by default as in user mode */
3649415e561fSbellard     env->eflags |= IF_MASK;
3650415e561fSbellard 
36516dbad63eSbellard     /* linux register setup */
3652d2fd1af7Sbellard #ifndef TARGET_ABI32
365384409ddbSj_mayer     env->regs[R_EAX] = regs->rax;
365484409ddbSj_mayer     env->regs[R_EBX] = regs->rbx;
365584409ddbSj_mayer     env->regs[R_ECX] = regs->rcx;
365684409ddbSj_mayer     env->regs[R_EDX] = regs->rdx;
365784409ddbSj_mayer     env->regs[R_ESI] = regs->rsi;
365884409ddbSj_mayer     env->regs[R_EDI] = regs->rdi;
365984409ddbSj_mayer     env->regs[R_EBP] = regs->rbp;
366084409ddbSj_mayer     env->regs[R_ESP] = regs->rsp;
366184409ddbSj_mayer     env->eip = regs->rip;
366284409ddbSj_mayer #else
36630ecfa993Sbellard     env->regs[R_EAX] = regs->eax;
36640ecfa993Sbellard     env->regs[R_EBX] = regs->ebx;
36650ecfa993Sbellard     env->regs[R_ECX] = regs->ecx;
36660ecfa993Sbellard     env->regs[R_EDX] = regs->edx;
36670ecfa993Sbellard     env->regs[R_ESI] = regs->esi;
36680ecfa993Sbellard     env->regs[R_EDI] = regs->edi;
36690ecfa993Sbellard     env->regs[R_EBP] = regs->ebp;
36700ecfa993Sbellard     env->regs[R_ESP] = regs->esp;
3671dab2ed99Sbellard     env->eip = regs->eip;
367284409ddbSj_mayer #endif
367331e31b8aSbellard 
3674f4beb510Sbellard     /* linux interrupt setup */
3675e441570fSbalrog #ifndef TARGET_ABI32
3676e441570fSbalrog     env->idt.limit = 511;
3677e441570fSbalrog #else
3678e441570fSbalrog     env->idt.limit = 255;
3679e441570fSbalrog #endif
3680e441570fSbalrog     env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
3681e441570fSbalrog                                 PROT_READ|PROT_WRITE,
3682e441570fSbalrog                                 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3683e441570fSbalrog     idt_table = g2h(env->idt.base);
3684f4beb510Sbellard     set_idt(0, 0);
3685f4beb510Sbellard     set_idt(1, 0);
3686f4beb510Sbellard     set_idt(2, 0);
3687f4beb510Sbellard     set_idt(3, 3);
3688f4beb510Sbellard     set_idt(4, 3);
3689ec95da6cSbellard     set_idt(5, 0);
3690f4beb510Sbellard     set_idt(6, 0);
3691f4beb510Sbellard     set_idt(7, 0);
3692f4beb510Sbellard     set_idt(8, 0);
3693f4beb510Sbellard     set_idt(9, 0);
3694f4beb510Sbellard     set_idt(10, 0);
3695f4beb510Sbellard     set_idt(11, 0);
3696f4beb510Sbellard     set_idt(12, 0);
3697f4beb510Sbellard     set_idt(13, 0);
3698f4beb510Sbellard     set_idt(14, 0);
3699f4beb510Sbellard     set_idt(15, 0);
3700f4beb510Sbellard     set_idt(16, 0);
3701f4beb510Sbellard     set_idt(17, 0);
3702f4beb510Sbellard     set_idt(18, 0);
3703f4beb510Sbellard     set_idt(19, 0);
3704f4beb510Sbellard     set_idt(0x80, 3);
3705f4beb510Sbellard 
37066dbad63eSbellard     /* linux segment setup */
37078d18e893Sbellard     {
37088d18e893Sbellard         uint64_t *gdt_table;
3709e441570fSbalrog         env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
3710e441570fSbalrog                                     PROT_READ|PROT_WRITE,
3711e441570fSbalrog                                     MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
37128d18e893Sbellard         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
3713e441570fSbalrog         gdt_table = g2h(env->gdt.base);
3714d2fd1af7Sbellard #ifdef TARGET_ABI32
3715f4beb510Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
3716f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3717f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
3718d2fd1af7Sbellard #else
3719d2fd1af7Sbellard         /* 64 bit code segment */
3720d2fd1af7Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
3721d2fd1af7Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3722d2fd1af7Sbellard                  DESC_L_MASK |
3723d2fd1af7Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
3724d2fd1af7Sbellard #endif
3725f4beb510Sbellard         write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
3726f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3727f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
37288d18e893Sbellard     }
37296dbad63eSbellard     cpu_x86_load_seg(env, R_CS, __USER_CS);
3730d2fd1af7Sbellard     cpu_x86_load_seg(env, R_SS, __USER_DS);
3731d2fd1af7Sbellard #ifdef TARGET_ABI32
37326dbad63eSbellard     cpu_x86_load_seg(env, R_DS, __USER_DS);
37336dbad63eSbellard     cpu_x86_load_seg(env, R_ES, __USER_DS);
37346dbad63eSbellard     cpu_x86_load_seg(env, R_FS, __USER_DS);
37356dbad63eSbellard     cpu_x86_load_seg(env, R_GS, __USER_DS);
3736d6eb40f6Sths     /* This hack makes Wine work... */
3737d6eb40f6Sths     env->segs[R_FS].selector = 0;
3738d2fd1af7Sbellard #else
3739d2fd1af7Sbellard     cpu_x86_load_seg(env, R_DS, 0);
3740d2fd1af7Sbellard     cpu_x86_load_seg(env, R_ES, 0);
3741d2fd1af7Sbellard     cpu_x86_load_seg(env, R_FS, 0);
3742d2fd1af7Sbellard     cpu_x86_load_seg(env, R_GS, 0);
3743d2fd1af7Sbellard #endif
3744b346ff46Sbellard #elif defined(TARGET_ARM)
3745b346ff46Sbellard     {
3746b346ff46Sbellard         int i;
3747b5ff1b31Sbellard         cpsr_write(env, regs->uregs[16], 0xffffffff);
3748b346ff46Sbellard         for(i = 0; i < 16; i++) {
3749b346ff46Sbellard             env->regs[i] = regs->uregs[i];
3750b346ff46Sbellard         }
3751d8fd2954SPaul Brook         /* Enable BE8.  */
3752d8fd2954SPaul Brook         if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
3753d8fd2954SPaul Brook             && (info->elf_flags & EF_ARM_BE8)) {
3754d8fd2954SPaul Brook             env->bswap_code = 1;
3755d8fd2954SPaul Brook         }
3756b346ff46Sbellard     }
3757d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
3758d2fbca94SGuan Xuetao     {
3759d2fbca94SGuan Xuetao         int i;
3760d2fbca94SGuan Xuetao         cpu_asr_write(env, regs->uregs[32], 0xffffffff);
3761d2fbca94SGuan Xuetao         for (i = 0; i < 32; i++) {
3762d2fbca94SGuan Xuetao             env->regs[i] = regs->uregs[i];
3763d2fbca94SGuan Xuetao         }
3764d2fbca94SGuan Xuetao     }
376593ac68bcSbellard #elif defined(TARGET_SPARC)
3766060366c5Sbellard     {
3767060366c5Sbellard         int i;
3768060366c5Sbellard 	env->pc = regs->pc;
3769060366c5Sbellard 	env->npc = regs->npc;
3770060366c5Sbellard         env->y = regs->y;
3771060366c5Sbellard         for(i = 0; i < 8; i++)
3772060366c5Sbellard             env->gregs[i] = regs->u_regs[i];
3773060366c5Sbellard         for(i = 0; i < 8; i++)
3774060366c5Sbellard             env->regwptr[i] = regs->u_regs[i + 8];
3775060366c5Sbellard     }
377667867308Sbellard #elif defined(TARGET_PPC)
377767867308Sbellard     {
377867867308Sbellard         int i;
37793fc6c082Sbellard 
37800411a972Sj_mayer #if defined(TARGET_PPC64)
37810411a972Sj_mayer #if defined(TARGET_ABI32)
37820411a972Sj_mayer         env->msr &= ~((target_ulong)1 << MSR_SF);
3783e85e7c6eSj_mayer #else
37840411a972Sj_mayer         env->msr |= (target_ulong)1 << MSR_SF;
37850411a972Sj_mayer #endif
378684409ddbSj_mayer #endif
378767867308Sbellard         env->nip = regs->nip;
378867867308Sbellard         for(i = 0; i < 32; i++) {
378967867308Sbellard             env->gpr[i] = regs->gpr[i];
379067867308Sbellard         }
379167867308Sbellard     }
3792e6e5906bSpbrook #elif defined(TARGET_M68K)
3793e6e5906bSpbrook     {
3794e6e5906bSpbrook         env->pc = regs->pc;
3795e6e5906bSpbrook         env->dregs[0] = regs->d0;
3796e6e5906bSpbrook         env->dregs[1] = regs->d1;
3797e6e5906bSpbrook         env->dregs[2] = regs->d2;
3798e6e5906bSpbrook         env->dregs[3] = regs->d3;
3799e6e5906bSpbrook         env->dregs[4] = regs->d4;
3800e6e5906bSpbrook         env->dregs[5] = regs->d5;
3801e6e5906bSpbrook         env->dregs[6] = regs->d6;
3802e6e5906bSpbrook         env->dregs[7] = regs->d7;
3803e6e5906bSpbrook         env->aregs[0] = regs->a0;
3804e6e5906bSpbrook         env->aregs[1] = regs->a1;
3805e6e5906bSpbrook         env->aregs[2] = regs->a2;
3806e6e5906bSpbrook         env->aregs[3] = regs->a3;
3807e6e5906bSpbrook         env->aregs[4] = regs->a4;
3808e6e5906bSpbrook         env->aregs[5] = regs->a5;
3809e6e5906bSpbrook         env->aregs[6] = regs->a6;
3810e6e5906bSpbrook         env->aregs[7] = regs->usp;
3811e6e5906bSpbrook         env->sr = regs->sr;
3812e6e5906bSpbrook         ts->sim_syscalls = 1;
3813e6e5906bSpbrook     }
3814b779e29eSEdgar E. Iglesias #elif defined(TARGET_MICROBLAZE)
3815b779e29eSEdgar E. Iglesias     {
3816b779e29eSEdgar E. Iglesias         env->regs[0] = regs->r0;
3817b779e29eSEdgar E. Iglesias         env->regs[1] = regs->r1;
3818b779e29eSEdgar E. Iglesias         env->regs[2] = regs->r2;
3819b779e29eSEdgar E. Iglesias         env->regs[3] = regs->r3;
3820b779e29eSEdgar E. Iglesias         env->regs[4] = regs->r4;
3821b779e29eSEdgar E. Iglesias         env->regs[5] = regs->r5;
3822b779e29eSEdgar E. Iglesias         env->regs[6] = regs->r6;
3823b779e29eSEdgar E. Iglesias         env->regs[7] = regs->r7;
3824b779e29eSEdgar E. Iglesias         env->regs[8] = regs->r8;
3825b779e29eSEdgar E. Iglesias         env->regs[9] = regs->r9;
3826b779e29eSEdgar E. Iglesias         env->regs[10] = regs->r10;
3827b779e29eSEdgar E. Iglesias         env->regs[11] = regs->r11;
3828b779e29eSEdgar E. Iglesias         env->regs[12] = regs->r12;
3829b779e29eSEdgar E. Iglesias         env->regs[13] = regs->r13;
3830b779e29eSEdgar E. Iglesias         env->regs[14] = regs->r14;
3831b779e29eSEdgar E. Iglesias         env->regs[15] = regs->r15;
3832b779e29eSEdgar E. Iglesias         env->regs[16] = regs->r16;
3833b779e29eSEdgar E. Iglesias         env->regs[17] = regs->r17;
3834b779e29eSEdgar E. Iglesias         env->regs[18] = regs->r18;
3835b779e29eSEdgar E. Iglesias         env->regs[19] = regs->r19;
3836b779e29eSEdgar E. Iglesias         env->regs[20] = regs->r20;
3837b779e29eSEdgar E. Iglesias         env->regs[21] = regs->r21;
3838b779e29eSEdgar E. Iglesias         env->regs[22] = regs->r22;
3839b779e29eSEdgar E. Iglesias         env->regs[23] = regs->r23;
3840b779e29eSEdgar E. Iglesias         env->regs[24] = regs->r24;
3841b779e29eSEdgar E. Iglesias         env->regs[25] = regs->r25;
3842b779e29eSEdgar E. Iglesias         env->regs[26] = regs->r26;
3843b779e29eSEdgar E. Iglesias         env->regs[27] = regs->r27;
3844b779e29eSEdgar E. Iglesias         env->regs[28] = regs->r28;
3845b779e29eSEdgar E. Iglesias         env->regs[29] = regs->r29;
3846b779e29eSEdgar E. Iglesias         env->regs[30] = regs->r30;
3847b779e29eSEdgar E. Iglesias         env->regs[31] = regs->r31;
3848b779e29eSEdgar E. Iglesias         env->sregs[SR_PC] = regs->pc;
3849b779e29eSEdgar E. Iglesias     }
3850048f6b4dSbellard #elif defined(TARGET_MIPS)
3851048f6b4dSbellard     {
3852048f6b4dSbellard         int i;
3853048f6b4dSbellard 
3854048f6b4dSbellard         for(i = 0; i < 32; i++) {
3855b5dc7732Sths             env->active_tc.gpr[i] = regs->regs[i];
3856048f6b4dSbellard         }
38570fddbbf2SNathan Froyd         env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
38580fddbbf2SNathan Froyd         if (regs->cp0_epc & 1) {
38590fddbbf2SNathan Froyd             env->hflags |= MIPS_HFLAG_M16;
38600fddbbf2SNathan Froyd         }
3861048f6b4dSbellard     }
3862d962783eSJia Liu #elif defined(TARGET_OPENRISC)
3863d962783eSJia Liu     {
3864d962783eSJia Liu         int i;
3865d962783eSJia Liu 
3866d962783eSJia Liu         for (i = 0; i < 32; i++) {
3867d962783eSJia Liu             env->gpr[i] = regs->gpr[i];
3868d962783eSJia Liu         }
3869d962783eSJia Liu 
3870d962783eSJia Liu         env->sr = regs->sr;
3871d962783eSJia Liu         env->pc = regs->pc;
3872d962783eSJia Liu     }
3873fdf9b3e8Sbellard #elif defined(TARGET_SH4)
3874fdf9b3e8Sbellard     {
3875fdf9b3e8Sbellard         int i;
3876fdf9b3e8Sbellard 
3877fdf9b3e8Sbellard         for(i = 0; i < 16; i++) {
3878fdf9b3e8Sbellard             env->gregs[i] = regs->regs[i];
3879fdf9b3e8Sbellard         }
3880fdf9b3e8Sbellard         env->pc = regs->pc;
3881fdf9b3e8Sbellard     }
38827a3148a9Sj_mayer #elif defined(TARGET_ALPHA)
38837a3148a9Sj_mayer     {
38847a3148a9Sj_mayer         int i;
38857a3148a9Sj_mayer 
38867a3148a9Sj_mayer         for(i = 0; i < 28; i++) {
3887992f48a0Sblueswir1             env->ir[i] = ((abi_ulong *)regs)[i];
38887a3148a9Sj_mayer         }
3889dad081eeSRichard Henderson         env->ir[IR_SP] = regs->usp;
38907a3148a9Sj_mayer         env->pc = regs->pc;
38917a3148a9Sj_mayer     }
389248733d19Sths #elif defined(TARGET_CRIS)
389348733d19Sths     {
389448733d19Sths 	    env->regs[0] = regs->r0;
389548733d19Sths 	    env->regs[1] = regs->r1;
389648733d19Sths 	    env->regs[2] = regs->r2;
389748733d19Sths 	    env->regs[3] = regs->r3;
389848733d19Sths 	    env->regs[4] = regs->r4;
389948733d19Sths 	    env->regs[5] = regs->r5;
390048733d19Sths 	    env->regs[6] = regs->r6;
390148733d19Sths 	    env->regs[7] = regs->r7;
390248733d19Sths 	    env->regs[8] = regs->r8;
390348733d19Sths 	    env->regs[9] = regs->r9;
390448733d19Sths 	    env->regs[10] = regs->r10;
390548733d19Sths 	    env->regs[11] = regs->r11;
390648733d19Sths 	    env->regs[12] = regs->r12;
390748733d19Sths 	    env->regs[13] = regs->r13;
390848733d19Sths 	    env->regs[14] = info->start_stack;
390948733d19Sths 	    env->regs[15] = regs->acr;
391048733d19Sths 	    env->pc = regs->erp;
391148733d19Sths     }
3912a4c075f1SUlrich Hecht #elif defined(TARGET_S390X)
3913a4c075f1SUlrich Hecht     {
3914a4c075f1SUlrich Hecht             int i;
3915a4c075f1SUlrich Hecht             for (i = 0; i < 16; i++) {
3916a4c075f1SUlrich Hecht                 env->regs[i] = regs->gprs[i];
3917a4c075f1SUlrich Hecht             }
3918a4c075f1SUlrich Hecht             env->psw.mask = regs->psw.mask;
3919a4c075f1SUlrich Hecht             env->psw.addr = regs->psw.addr;
3920a4c075f1SUlrich Hecht     }
3921b346ff46Sbellard #else
3922b346ff46Sbellard #error unsupported target CPU
3923b346ff46Sbellard #endif
392431e31b8aSbellard 
3925d2fbca94SGuan Xuetao #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
3926a87295e8Spbrook     ts->stack_base = info->start_stack;
3927a87295e8Spbrook     ts->heap_base = info->brk;
3928a87295e8Spbrook     /* This will be filled in on the first SYS_HEAPINFO call.  */
3929a87295e8Spbrook     ts->heap_limit = 0;
3930a87295e8Spbrook #endif
3931a87295e8Spbrook 
393274c33bedSbellard     if (gdbstub_port) {
3933ff7a981aSPeter Maydell         if (gdbserver_start(gdbstub_port) < 0) {
3934ff7a981aSPeter Maydell             fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
3935ff7a981aSPeter Maydell                     gdbstub_port);
3936ff7a981aSPeter Maydell             exit(1);
3937ff7a981aSPeter Maydell         }
39381fddef4bSbellard         gdb_handlesig(env, 0);
39391fddef4bSbellard     }
39401b6b029eSbellard     cpu_loop(env);
39411b6b029eSbellard     /* never exits */
394231e31b8aSbellard     return 0;
394331e31b8aSbellard }
3944