xref: /qemu/linux-user/main.c (revision b4916d7b)
131e31b8aSbellard /*
293ac68bcSbellard  *  qemu user main
331e31b8aSbellard  *
468d0f70eSbellard  *  Copyright (c) 2003-2008 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1831e31b8aSbellard  */
1931e31b8aSbellard #include <stdlib.h>
2031e31b8aSbellard #include <stdio.h>
2131e31b8aSbellard #include <stdarg.h>
2204369ff2Sbellard #include <string.h>
2331e31b8aSbellard #include <errno.h>
240ecfa993Sbellard #include <unistd.h>
25e441570fSbalrog #include <sys/mman.h>
26edf8e2afSMika Westerberg #include <sys/syscall.h>
27703e0e89SRichard Henderson #include <sys/resource.h>
2831e31b8aSbellard 
293ef693a0Sbellard #include "qemu.h"
30ca10f867Saurel32 #include "qemu-common.h"
31902b3d5cSmalc #include "cache-utils.h"
322b41f10eSBlue Swirl #include "cpu.h"
339002ec79SRichard Henderson #include "tcg.h"
3429e922b6SBlue Swirl #include "qemu-timer.h"
3504a6dfebSaurel32 #include "envlist.h"
3604a6dfebSaurel32 
373ef693a0Sbellard #define DEBUG_LOGFILE "/tmp/qemu.log"
38586314f2Sbellard 
39d088d664Saurel32 char *exec_path;
40d088d664Saurel32 
411b530a6dSaurel32 int singlestep;
42fc9c5412SJohannes Schauer const char *filename;
43fc9c5412SJohannes Schauer const char *argv0;
44fc9c5412SJohannes Schauer int gdbstub_port;
45fc9c5412SJohannes Schauer envlist_t *envlist;
46fc9c5412SJohannes Schauer const char *cpu_model;
47379f6698SPaul Brook unsigned long mmap_min_addr;
4814f24e14SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE)
49379f6698SPaul Brook unsigned long guest_base;
50379f6698SPaul Brook int have_guest_base;
5168a1c816SPaul Brook unsigned long reserved_va;
52379f6698SPaul Brook #endif
531b530a6dSaurel32 
54fc9c5412SJohannes Schauer static void usage(void);
55fc9c5412SJohannes Schauer 
567ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
57c5937220Spbrook const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
58586314f2Sbellard 
599de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
609de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
619de5e440Sbellard    by remapping the process stack directly at the right place */
62703e0e89SRichard Henderson unsigned long guest_stack_size = 8 * 1024 * 1024UL;
6331e31b8aSbellard 
6431e31b8aSbellard void gemu_log(const char *fmt, ...)
6531e31b8aSbellard {
6631e31b8aSbellard     va_list ap;
6731e31b8aSbellard 
6831e31b8aSbellard     va_start(ap, fmt);
6931e31b8aSbellard     vfprintf(stderr, fmt, ap);
7031e31b8aSbellard     va_end(ap);
7131e31b8aSbellard }
7231e31b8aSbellard 
738fcd3692Sblueswir1 #if defined(TARGET_I386)
74a541f297Sbellard int cpu_get_pic_interrupt(CPUState *env)
7592ccca6aSbellard {
7692ccca6aSbellard     return -1;
7792ccca6aSbellard }
788fcd3692Sblueswir1 #endif
7992ccca6aSbellard 
8028ab0e2eSbellard /* timers for rdtsc */
8128ab0e2eSbellard 
821dce7c3cSbellard #if 0
8328ab0e2eSbellard 
8428ab0e2eSbellard static uint64_t emu_time;
8528ab0e2eSbellard 
8628ab0e2eSbellard int64_t cpu_get_real_ticks(void)
8728ab0e2eSbellard {
8828ab0e2eSbellard     return emu_time++;
8928ab0e2eSbellard }
9028ab0e2eSbellard 
9128ab0e2eSbellard #endif
9228ab0e2eSbellard 
932f7bb878SJuan Quintela #if defined(CONFIG_USE_NPTL)
94d5975363Spbrook /***********************************************************/
95d5975363Spbrook /* Helper routines for implementing atomic operations.  */
96d5975363Spbrook 
97d5975363Spbrook /* To implement exclusive operations we force all cpus to syncronise.
98d5975363Spbrook    We don't require a full sync, only that no cpus are executing guest code.
99d5975363Spbrook    The alternative is to map target atomic ops onto host equivalents,
100d5975363Spbrook    which requires quite a lot of per host/target work.  */
101c2764719Spbrook static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
102d5975363Spbrook static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
103d5975363Spbrook static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
104d5975363Spbrook static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
105d5975363Spbrook static int pending_cpus;
106d5975363Spbrook 
107d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
108d5975363Spbrook void fork_start(void)
109d5975363Spbrook {
110d5975363Spbrook     pthread_mutex_lock(&tb_lock);
111d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
112d032d1b4SRiku Voipio     mmap_fork_start();
113d5975363Spbrook }
114d5975363Spbrook 
115d5975363Spbrook void fork_end(int child)
116d5975363Spbrook {
117d032d1b4SRiku Voipio     mmap_fork_end(child);
118d5975363Spbrook     if (child) {
119d5975363Spbrook         /* Child processes created by fork() only have a single thread.
120d5975363Spbrook            Discard information about the parent threads.  */
121d5975363Spbrook         first_cpu = thread_env;
122d5975363Spbrook         thread_env->next_cpu = NULL;
123d5975363Spbrook         pending_cpus = 0;
124d5975363Spbrook         pthread_mutex_init(&exclusive_lock, NULL);
125c2764719Spbrook         pthread_mutex_init(&cpu_list_mutex, NULL);
126d5975363Spbrook         pthread_cond_init(&exclusive_cond, NULL);
127d5975363Spbrook         pthread_cond_init(&exclusive_resume, NULL);
128d5975363Spbrook         pthread_mutex_init(&tb_lock, NULL);
1292b1319c8Saurel32         gdbserver_fork(thread_env);
130d5975363Spbrook     } else {
131d5975363Spbrook         pthread_mutex_unlock(&exclusive_lock);
132d5975363Spbrook         pthread_mutex_unlock(&tb_lock);
133d5975363Spbrook     }
134d5975363Spbrook }
135d5975363Spbrook 
136d5975363Spbrook /* Wait for pending exclusive operations to complete.  The exclusive lock
137d5975363Spbrook    must be held.  */
138d5975363Spbrook static inline void exclusive_idle(void)
139d5975363Spbrook {
140d5975363Spbrook     while (pending_cpus) {
141d5975363Spbrook         pthread_cond_wait(&exclusive_resume, &exclusive_lock);
142d5975363Spbrook     }
143d5975363Spbrook }
144d5975363Spbrook 
145d5975363Spbrook /* Start an exclusive operation.
146d5975363Spbrook    Must only be called from outside cpu_arm_exec.   */
147d5975363Spbrook static inline void start_exclusive(void)
148d5975363Spbrook {
149d5975363Spbrook     CPUState *other;
150d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
151d5975363Spbrook     exclusive_idle();
152d5975363Spbrook 
153d5975363Spbrook     pending_cpus = 1;
154d5975363Spbrook     /* Make all other cpus stop executing.  */
155d5975363Spbrook     for (other = first_cpu; other; other = other->next_cpu) {
156d5975363Spbrook         if (other->running) {
157d5975363Spbrook             pending_cpus++;
1583098dba0Saurel32             cpu_exit(other);
159d5975363Spbrook         }
160d5975363Spbrook     }
161d5975363Spbrook     if (pending_cpus > 1) {
162d5975363Spbrook         pthread_cond_wait(&exclusive_cond, &exclusive_lock);
163d5975363Spbrook     }
164d5975363Spbrook }
165d5975363Spbrook 
166d5975363Spbrook /* Finish an exclusive operation.  */
167d5975363Spbrook static inline void end_exclusive(void)
168d5975363Spbrook {
169d5975363Spbrook     pending_cpus = 0;
170d5975363Spbrook     pthread_cond_broadcast(&exclusive_resume);
171d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
172d5975363Spbrook }
173d5975363Spbrook 
174d5975363Spbrook /* Wait for exclusive ops to finish, and begin cpu execution.  */
175d5975363Spbrook static inline void cpu_exec_start(CPUState *env)
176d5975363Spbrook {
177d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
178d5975363Spbrook     exclusive_idle();
179d5975363Spbrook     env->running = 1;
180d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
181d5975363Spbrook }
182d5975363Spbrook 
183d5975363Spbrook /* Mark cpu as not executing, and release pending exclusive ops.  */
184d5975363Spbrook static inline void cpu_exec_end(CPUState *env)
185d5975363Spbrook {
186d5975363Spbrook     pthread_mutex_lock(&exclusive_lock);
187d5975363Spbrook     env->running = 0;
188d5975363Spbrook     if (pending_cpus > 1) {
189d5975363Spbrook         pending_cpus--;
190d5975363Spbrook         if (pending_cpus == 1) {
191d5975363Spbrook             pthread_cond_signal(&exclusive_cond);
192d5975363Spbrook         }
193d5975363Spbrook     }
194d5975363Spbrook     exclusive_idle();
195d5975363Spbrook     pthread_mutex_unlock(&exclusive_lock);
196d5975363Spbrook }
197c2764719Spbrook 
198c2764719Spbrook void cpu_list_lock(void)
199c2764719Spbrook {
200c2764719Spbrook     pthread_mutex_lock(&cpu_list_mutex);
201c2764719Spbrook }
202c2764719Spbrook 
203c2764719Spbrook void cpu_list_unlock(void)
204c2764719Spbrook {
205c2764719Spbrook     pthread_mutex_unlock(&cpu_list_mutex);
206c2764719Spbrook }
2072f7bb878SJuan Quintela #else /* if !CONFIG_USE_NPTL */
208d5975363Spbrook /* These are no-ops because we are not threadsafe.  */
209d5975363Spbrook static inline void cpu_exec_start(CPUState *env)
210d5975363Spbrook {
211d5975363Spbrook }
212d5975363Spbrook 
213d5975363Spbrook static inline void cpu_exec_end(CPUState *env)
214d5975363Spbrook {
215d5975363Spbrook }
216d5975363Spbrook 
217d5975363Spbrook static inline void start_exclusive(void)
218d5975363Spbrook {
219d5975363Spbrook }
220d5975363Spbrook 
221d5975363Spbrook static inline void end_exclusive(void)
222d5975363Spbrook {
223d5975363Spbrook }
224d5975363Spbrook 
225d5975363Spbrook void fork_start(void)
226d5975363Spbrook {
227d5975363Spbrook }
228d5975363Spbrook 
229d5975363Spbrook void fork_end(int child)
230d5975363Spbrook {
2312b1319c8Saurel32     if (child) {
2322b1319c8Saurel32         gdbserver_fork(thread_env);
2332b1319c8Saurel32     }
234d5975363Spbrook }
235c2764719Spbrook 
236c2764719Spbrook void cpu_list_lock(void)
237c2764719Spbrook {
238c2764719Spbrook }
239c2764719Spbrook 
240c2764719Spbrook void cpu_list_unlock(void)
241c2764719Spbrook {
242c2764719Spbrook }
243d5975363Spbrook #endif
244d5975363Spbrook 
245d5975363Spbrook 
246a541f297Sbellard #ifdef TARGET_I386
247a541f297Sbellard /***********************************************************/
248a541f297Sbellard /* CPUX86 core interface */
249a541f297Sbellard 
25002a1602eSbellard void cpu_smm_update(CPUState *env)
25102a1602eSbellard {
25202a1602eSbellard }
25302a1602eSbellard 
25428ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env)
25528ab0e2eSbellard {
25628ab0e2eSbellard     return cpu_get_real_ticks();
25728ab0e2eSbellard }
25828ab0e2eSbellard 
259f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
260f4beb510Sbellard                      int flags)
2616dbad63eSbellard {
262f4beb510Sbellard     unsigned int e1, e2;
26353a5960aSpbrook     uint32_t *p;
2646dbad63eSbellard     e1 = (addr << 16) | (limit & 0xffff);
2656dbad63eSbellard     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
266f4beb510Sbellard     e2 |= flags;
26753a5960aSpbrook     p = ptr;
268d538e8f5Smalc     p[0] = tswap32(e1);
269d538e8f5Smalc     p[1] = tswap32(e2);
270f4beb510Sbellard }
271f4beb510Sbellard 
272e441570fSbalrog static uint64_t *idt_table;
273eb38c52cSblueswir1 #ifdef TARGET_X86_64
274d2fd1af7Sbellard static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
275d2fd1af7Sbellard                        uint64_t addr, unsigned int sel)
276d2fd1af7Sbellard {
2774dbc422bSbellard     uint32_t *p, e1, e2;
278d2fd1af7Sbellard     e1 = (addr & 0xffff) | (sel << 16);
279d2fd1af7Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
280d2fd1af7Sbellard     p = ptr;
2814dbc422bSbellard     p[0] = tswap32(e1);
2824dbc422bSbellard     p[1] = tswap32(e2);
2834dbc422bSbellard     p[2] = tswap32(addr >> 32);
2844dbc422bSbellard     p[3] = 0;
285d2fd1af7Sbellard }
286d2fd1af7Sbellard /* only dpl matters as we do only user space emulation */
287d2fd1af7Sbellard static void set_idt(int n, unsigned int dpl)
288d2fd1af7Sbellard {
289d2fd1af7Sbellard     set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
290d2fd1af7Sbellard }
291d2fd1af7Sbellard #else
292f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
293d2fd1af7Sbellard                      uint32_t addr, unsigned int sel)
294f4beb510Sbellard {
2954dbc422bSbellard     uint32_t *p, e1, e2;
296f4beb510Sbellard     e1 = (addr & 0xffff) | (sel << 16);
297f4beb510Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
29853a5960aSpbrook     p = ptr;
2994dbc422bSbellard     p[0] = tswap32(e1);
3004dbc422bSbellard     p[1] = tswap32(e2);
3016dbad63eSbellard }
3026dbad63eSbellard 
303f4beb510Sbellard /* only dpl matters as we do only user space emulation */
304f4beb510Sbellard static void set_idt(int n, unsigned int dpl)
305f4beb510Sbellard {
306f4beb510Sbellard     set_gate(idt_table + n, 0, dpl, 0, 0);
307f4beb510Sbellard }
308d2fd1af7Sbellard #endif
30931e31b8aSbellard 
31089e957e7Sbellard void cpu_loop(CPUX86State *env)
311bc8a22ccSbellard {
312bc8a22ccSbellard     int trapnr;
313992f48a0Sblueswir1     abi_ulong pc;
314c227f099SAnthony Liguori     target_siginfo_t info;
315bc8a22ccSbellard 
316bc8a22ccSbellard     for(;;) {
317bc8a22ccSbellard         trapnr = cpu_x86_exec(env);
318bc8a22ccSbellard         switch(trapnr) {
319f4beb510Sbellard         case 0x80:
320d2fd1af7Sbellard             /* linux syscall from int $0x80 */
3211b6b029eSbellard             env->regs[R_EAX] = do_syscall(env,
3221b6b029eSbellard                                           env->regs[R_EAX],
3231b6b029eSbellard                                           env->regs[R_EBX],
3241b6b029eSbellard                                           env->regs[R_ECX],
3251b6b029eSbellard                                           env->regs[R_EDX],
3261b6b029eSbellard                                           env->regs[R_ESI],
3271b6b029eSbellard                                           env->regs[R_EDI],
3285945cfcbSPeter Maydell                                           env->regs[R_EBP],
3295945cfcbSPeter Maydell                                           0, 0);
330f4beb510Sbellard             break;
331d2fd1af7Sbellard #ifndef TARGET_ABI32
332d2fd1af7Sbellard         case EXCP_SYSCALL:
3335ba18547SStefan Weil             /* linux syscall from syscall instruction */
334d2fd1af7Sbellard             env->regs[R_EAX] = do_syscall(env,
335d2fd1af7Sbellard                                           env->regs[R_EAX],
336d2fd1af7Sbellard                                           env->regs[R_EDI],
337d2fd1af7Sbellard                                           env->regs[R_ESI],
338d2fd1af7Sbellard                                           env->regs[R_EDX],
339d2fd1af7Sbellard                                           env->regs[10],
340d2fd1af7Sbellard                                           env->regs[8],
3415945cfcbSPeter Maydell                                           env->regs[9],
3425945cfcbSPeter Maydell                                           0, 0);
343d2fd1af7Sbellard             env->eip = env->exception_next_eip;
344d2fd1af7Sbellard             break;
345d2fd1af7Sbellard #endif
346f4beb510Sbellard         case EXCP0B_NOSEG:
347f4beb510Sbellard         case EXCP0C_STACK:
348f4beb510Sbellard             info.si_signo = SIGBUS;
349f4beb510Sbellard             info.si_errno = 0;
350f4beb510Sbellard             info.si_code = TARGET_SI_KERNEL;
351f4beb510Sbellard             info._sifields._sigfault._addr = 0;
352624f7979Spbrook             queue_signal(env, info.si_signo, &info);
353f4beb510Sbellard             break;
354f4beb510Sbellard         case EXCP0D_GPF:
355d2fd1af7Sbellard             /* XXX: potential problem if ABI32 */
35684409ddbSj_mayer #ifndef TARGET_X86_64
357f4beb510Sbellard             if (env->eflags & VM_MASK) {
358f4beb510Sbellard                 handle_vm86_fault(env);
35984409ddbSj_mayer             } else
36084409ddbSj_mayer #endif
36184409ddbSj_mayer             {
3629de5e440Sbellard                 info.si_signo = SIGSEGV;
3639de5e440Sbellard                 info.si_errno = 0;
364b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
3659de5e440Sbellard                 info._sifields._sigfault._addr = 0;
366624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
3671b6b029eSbellard             }
3681b6b029eSbellard             break;
369b689bc57Sbellard         case EXCP0E_PAGE:
370b689bc57Sbellard             info.si_signo = SIGSEGV;
371b689bc57Sbellard             info.si_errno = 0;
372b689bc57Sbellard             if (!(env->error_code & 1))
373b689bc57Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
374b689bc57Sbellard             else
375b689bc57Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
376970a87a6Sbellard             info._sifields._sigfault._addr = env->cr[2];
377624f7979Spbrook             queue_signal(env, info.si_signo, &info);
378b689bc57Sbellard             break;
3799de5e440Sbellard         case EXCP00_DIVZ:
38084409ddbSj_mayer #ifndef TARGET_X86_64
381bc8a22ccSbellard             if (env->eflags & VM_MASK) {
382447db213Sbellard                 handle_vm86_trap(env, trapnr);
38384409ddbSj_mayer             } else
38484409ddbSj_mayer #endif
38584409ddbSj_mayer             {
3869de5e440Sbellard                 /* division by zero */
3879de5e440Sbellard                 info.si_signo = SIGFPE;
3889de5e440Sbellard                 info.si_errno = 0;
3899de5e440Sbellard                 info.si_code = TARGET_FPE_INTDIV;
3909de5e440Sbellard                 info._sifields._sigfault._addr = env->eip;
391624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
392bc8a22ccSbellard             }
3939de5e440Sbellard             break;
39401df040bSaliguori         case EXCP01_DB:
395447db213Sbellard         case EXCP03_INT3:
39684409ddbSj_mayer #ifndef TARGET_X86_64
397447db213Sbellard             if (env->eflags & VM_MASK) {
398447db213Sbellard                 handle_vm86_trap(env, trapnr);
39984409ddbSj_mayer             } else
40084409ddbSj_mayer #endif
40184409ddbSj_mayer             {
402447db213Sbellard                 info.si_signo = SIGTRAP;
403447db213Sbellard                 info.si_errno = 0;
40401df040bSaliguori                 if (trapnr == EXCP01_DB) {
405447db213Sbellard                     info.si_code = TARGET_TRAP_BRKPT;
406447db213Sbellard                     info._sifields._sigfault._addr = env->eip;
407447db213Sbellard                 } else {
408447db213Sbellard                     info.si_code = TARGET_SI_KERNEL;
409447db213Sbellard                     info._sifields._sigfault._addr = 0;
410447db213Sbellard                 }
411624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
412447db213Sbellard             }
413447db213Sbellard             break;
4149de5e440Sbellard         case EXCP04_INTO:
4159de5e440Sbellard         case EXCP05_BOUND:
41684409ddbSj_mayer #ifndef TARGET_X86_64
417bc8a22ccSbellard             if (env->eflags & VM_MASK) {
418447db213Sbellard                 handle_vm86_trap(env, trapnr);
41984409ddbSj_mayer             } else
42084409ddbSj_mayer #endif
42184409ddbSj_mayer             {
4229de5e440Sbellard                 info.si_signo = SIGSEGV;
4239de5e440Sbellard                 info.si_errno = 0;
424b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
4259de5e440Sbellard                 info._sifields._sigfault._addr = 0;
426624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
427bc8a22ccSbellard             }
4289de5e440Sbellard             break;
4299de5e440Sbellard         case EXCP06_ILLOP:
4309de5e440Sbellard             info.si_signo = SIGILL;
4319de5e440Sbellard             info.si_errno = 0;
4329de5e440Sbellard             info.si_code = TARGET_ILL_ILLOPN;
4339de5e440Sbellard             info._sifields._sigfault._addr = env->eip;
434624f7979Spbrook             queue_signal(env, info.si_signo, &info);
4359de5e440Sbellard             break;
4369de5e440Sbellard         case EXCP_INTERRUPT:
4379de5e440Sbellard             /* just indicate that signals should be handled asap */
4389de5e440Sbellard             break;
4391fddef4bSbellard         case EXCP_DEBUG:
4401fddef4bSbellard             {
4411fddef4bSbellard                 int sig;
4421fddef4bSbellard 
4431fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
4441fddef4bSbellard                 if (sig)
4451fddef4bSbellard                   {
4461fddef4bSbellard                     info.si_signo = sig;
4471fddef4bSbellard                     info.si_errno = 0;
4481fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
449624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
4501fddef4bSbellard                   }
4511fddef4bSbellard             }
4521fddef4bSbellard             break;
4531b6b029eSbellard         default:
454970a87a6Sbellard             pc = env->segs[R_CS].base + env->eip;
455bc8a22ccSbellard             fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
456bc8a22ccSbellard                     (long)pc, trapnr);
4571b6b029eSbellard             abort();
4581b6b029eSbellard         }
45966fb9763Sbellard         process_pending_signals(env);
4601b6b029eSbellard     }
4611b6b029eSbellard }
462b346ff46Sbellard #endif
463b346ff46Sbellard 
464b346ff46Sbellard #ifdef TARGET_ARM
465b346ff46Sbellard 
46697cc7560SDr. David Alan Gilbert /*
46797cc7560SDr. David Alan Gilbert  * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
46897cc7560SDr. David Alan Gilbert  * Input:
46997cc7560SDr. David Alan Gilbert  * r0 = pointer to oldval
47097cc7560SDr. David Alan Gilbert  * r1 = pointer to newval
47197cc7560SDr. David Alan Gilbert  * r2 = pointer to target value
47297cc7560SDr. David Alan Gilbert  *
47397cc7560SDr. David Alan Gilbert  * Output:
47497cc7560SDr. David Alan Gilbert  * r0 = 0 if *ptr was changed, non-0 if no exchange happened
47597cc7560SDr. David Alan Gilbert  * C set if *ptr was changed, clear if no exchange happened
47697cc7560SDr. David Alan Gilbert  *
47797cc7560SDr. David Alan Gilbert  * Note segv's in kernel helpers are a bit tricky, we can set the
47897cc7560SDr. David Alan Gilbert  * data address sensibly but the PC address is just the entry point.
47997cc7560SDr. David Alan Gilbert  */
48097cc7560SDr. David Alan Gilbert static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
48197cc7560SDr. David Alan Gilbert {
48297cc7560SDr. David Alan Gilbert     uint64_t oldval, newval, val;
48397cc7560SDr. David Alan Gilbert     uint32_t addr, cpsr;
48497cc7560SDr. David Alan Gilbert     target_siginfo_t info;
48597cc7560SDr. David Alan Gilbert 
48697cc7560SDr. David Alan Gilbert     /* Based on the 32 bit code in do_kernel_trap */
48797cc7560SDr. David Alan Gilbert 
48897cc7560SDr. David Alan Gilbert     /* XXX: This only works between threads, not between processes.
48997cc7560SDr. David Alan Gilbert        It's probably possible to implement this with native host
49097cc7560SDr. David Alan Gilbert        operations. However things like ldrex/strex are much harder so
49197cc7560SDr. David Alan Gilbert        there's not much point trying.  */
49297cc7560SDr. David Alan Gilbert     start_exclusive();
49397cc7560SDr. David Alan Gilbert     cpsr = cpsr_read(env);
49497cc7560SDr. David Alan Gilbert     addr = env->regs[2];
49597cc7560SDr. David Alan Gilbert 
49697cc7560SDr. David Alan Gilbert     if (get_user_u64(oldval, env->regs[0])) {
49797cc7560SDr. David Alan Gilbert         env->cp15.c6_data = env->regs[0];
49897cc7560SDr. David Alan Gilbert         goto segv;
49997cc7560SDr. David Alan Gilbert     };
50097cc7560SDr. David Alan Gilbert 
50197cc7560SDr. David Alan Gilbert     if (get_user_u64(newval, env->regs[1])) {
50297cc7560SDr. David Alan Gilbert         env->cp15.c6_data = env->regs[1];
50397cc7560SDr. David Alan Gilbert         goto segv;
50497cc7560SDr. David Alan Gilbert     };
50597cc7560SDr. David Alan Gilbert 
50697cc7560SDr. David Alan Gilbert     if (get_user_u64(val, addr)) {
50797cc7560SDr. David Alan Gilbert         env->cp15.c6_data = addr;
50897cc7560SDr. David Alan Gilbert         goto segv;
50997cc7560SDr. David Alan Gilbert     }
51097cc7560SDr. David Alan Gilbert 
51197cc7560SDr. David Alan Gilbert     if (val == oldval) {
51297cc7560SDr. David Alan Gilbert         val = newval;
51397cc7560SDr. David Alan Gilbert 
51497cc7560SDr. David Alan Gilbert         if (put_user_u64(val, addr)) {
51597cc7560SDr. David Alan Gilbert             env->cp15.c6_data = addr;
51697cc7560SDr. David Alan Gilbert             goto segv;
51797cc7560SDr. David Alan Gilbert         };
51897cc7560SDr. David Alan Gilbert 
51997cc7560SDr. David Alan Gilbert         env->regs[0] = 0;
52097cc7560SDr. David Alan Gilbert         cpsr |= CPSR_C;
52197cc7560SDr. David Alan Gilbert     } else {
52297cc7560SDr. David Alan Gilbert         env->regs[0] = -1;
52397cc7560SDr. David Alan Gilbert         cpsr &= ~CPSR_C;
52497cc7560SDr. David Alan Gilbert     }
52597cc7560SDr. David Alan Gilbert     cpsr_write(env, cpsr, CPSR_C);
52697cc7560SDr. David Alan Gilbert     end_exclusive();
52797cc7560SDr. David Alan Gilbert     return;
52897cc7560SDr. David Alan Gilbert 
52997cc7560SDr. David Alan Gilbert segv:
53097cc7560SDr. David Alan Gilbert     end_exclusive();
53197cc7560SDr. David Alan Gilbert     /* We get the PC of the entry address - which is as good as anything,
53297cc7560SDr. David Alan Gilbert        on a real kernel what you get depends on which mode it uses. */
53397cc7560SDr. David Alan Gilbert     info.si_signo = SIGSEGV;
53497cc7560SDr. David Alan Gilbert     info.si_errno = 0;
53597cc7560SDr. David Alan Gilbert     /* XXX: check env->error_code */
53697cc7560SDr. David Alan Gilbert     info.si_code = TARGET_SEGV_MAPERR;
53797cc7560SDr. David Alan Gilbert     info._sifields._sigfault._addr = env->cp15.c6_data;
53897cc7560SDr. David Alan Gilbert     queue_signal(env, info.si_signo, &info);
53997cc7560SDr. David Alan Gilbert 
54097cc7560SDr. David Alan Gilbert     end_exclusive();
54197cc7560SDr. David Alan Gilbert }
54297cc7560SDr. David Alan Gilbert 
543fbb4a2e3Spbrook /* Handle a jump to the kernel code page.  */
544fbb4a2e3Spbrook static int
545fbb4a2e3Spbrook do_kernel_trap(CPUARMState *env)
546fbb4a2e3Spbrook {
547fbb4a2e3Spbrook     uint32_t addr;
548fbb4a2e3Spbrook     uint32_t cpsr;
549fbb4a2e3Spbrook     uint32_t val;
550fbb4a2e3Spbrook 
551fbb4a2e3Spbrook     switch (env->regs[15]) {
552fbb4a2e3Spbrook     case 0xffff0fa0: /* __kernel_memory_barrier */
553fbb4a2e3Spbrook         /* ??? No-op. Will need to do better for SMP.  */
554fbb4a2e3Spbrook         break;
555fbb4a2e3Spbrook     case 0xffff0fc0: /* __kernel_cmpxchg */
556d5975363Spbrook          /* XXX: This only works between threads, not between processes.
557d5975363Spbrook             It's probably possible to implement this with native host
558d5975363Spbrook             operations. However things like ldrex/strex are much harder so
559d5975363Spbrook             there's not much point trying.  */
560d5975363Spbrook         start_exclusive();
561fbb4a2e3Spbrook         cpsr = cpsr_read(env);
562fbb4a2e3Spbrook         addr = env->regs[2];
563fbb4a2e3Spbrook         /* FIXME: This should SEGV if the access fails.  */
564fbb4a2e3Spbrook         if (get_user_u32(val, addr))
565fbb4a2e3Spbrook             val = ~env->regs[0];
566fbb4a2e3Spbrook         if (val == env->regs[0]) {
567fbb4a2e3Spbrook             val = env->regs[1];
568fbb4a2e3Spbrook             /* FIXME: Check for segfaults.  */
569fbb4a2e3Spbrook             put_user_u32(val, addr);
570fbb4a2e3Spbrook             env->regs[0] = 0;
571fbb4a2e3Spbrook             cpsr |= CPSR_C;
572fbb4a2e3Spbrook         } else {
573fbb4a2e3Spbrook             env->regs[0] = -1;
574fbb4a2e3Spbrook             cpsr &= ~CPSR_C;
575fbb4a2e3Spbrook         }
576fbb4a2e3Spbrook         cpsr_write(env, cpsr, CPSR_C);
577d5975363Spbrook         end_exclusive();
578fbb4a2e3Spbrook         break;
579fbb4a2e3Spbrook     case 0xffff0fe0: /* __kernel_get_tls */
580fbb4a2e3Spbrook         env->regs[0] = env->cp15.c13_tls2;
581fbb4a2e3Spbrook         break;
58297cc7560SDr. David Alan Gilbert     case 0xffff0f60: /* __kernel_cmpxchg64 */
58397cc7560SDr. David Alan Gilbert         arm_kernel_cmpxchg64_helper(env);
58497cc7560SDr. David Alan Gilbert         break;
58597cc7560SDr. David Alan Gilbert 
586fbb4a2e3Spbrook     default:
587fbb4a2e3Spbrook         return 1;
588fbb4a2e3Spbrook     }
589fbb4a2e3Spbrook     /* Jump back to the caller.  */
590fbb4a2e3Spbrook     addr = env->regs[14];
591fbb4a2e3Spbrook     if (addr & 1) {
592fbb4a2e3Spbrook         env->thumb = 1;
593fbb4a2e3Spbrook         addr &= ~1;
594fbb4a2e3Spbrook     }
595fbb4a2e3Spbrook     env->regs[15] = addr;
596fbb4a2e3Spbrook 
597fbb4a2e3Spbrook     return 0;
598fbb4a2e3Spbrook }
599fbb4a2e3Spbrook 
600426f5abcSPaul Brook static int do_strex(CPUARMState *env)
601426f5abcSPaul Brook {
602426f5abcSPaul Brook     uint32_t val;
603426f5abcSPaul Brook     int size;
604426f5abcSPaul Brook     int rc = 1;
605426f5abcSPaul Brook     int segv = 0;
606426f5abcSPaul Brook     uint32_t addr;
607426f5abcSPaul Brook     start_exclusive();
608426f5abcSPaul Brook     addr = env->exclusive_addr;
609426f5abcSPaul Brook     if (addr != env->exclusive_test) {
610426f5abcSPaul Brook         goto fail;
611426f5abcSPaul Brook     }
612426f5abcSPaul Brook     size = env->exclusive_info & 0xf;
613426f5abcSPaul Brook     switch (size) {
614426f5abcSPaul Brook     case 0:
615426f5abcSPaul Brook         segv = get_user_u8(val, addr);
616426f5abcSPaul Brook         break;
617426f5abcSPaul Brook     case 1:
618426f5abcSPaul Brook         segv = get_user_u16(val, addr);
619426f5abcSPaul Brook         break;
620426f5abcSPaul Brook     case 2:
621426f5abcSPaul Brook     case 3:
622426f5abcSPaul Brook         segv = get_user_u32(val, addr);
623426f5abcSPaul Brook         break;
624f7001a3bSAurelien Jarno     default:
625f7001a3bSAurelien Jarno         abort();
626426f5abcSPaul Brook     }
627426f5abcSPaul Brook     if (segv) {
628426f5abcSPaul Brook         env->cp15.c6_data = addr;
629426f5abcSPaul Brook         goto done;
630426f5abcSPaul Brook     }
631426f5abcSPaul Brook     if (val != env->exclusive_val) {
632426f5abcSPaul Brook         goto fail;
633426f5abcSPaul Brook     }
634426f5abcSPaul Brook     if (size == 3) {
635426f5abcSPaul Brook         segv = get_user_u32(val, addr + 4);
636426f5abcSPaul Brook         if (segv) {
637426f5abcSPaul Brook             env->cp15.c6_data = addr + 4;
638426f5abcSPaul Brook             goto done;
639426f5abcSPaul Brook         }
640426f5abcSPaul Brook         if (val != env->exclusive_high) {
641426f5abcSPaul Brook             goto fail;
642426f5abcSPaul Brook         }
643426f5abcSPaul Brook     }
644426f5abcSPaul Brook     val = env->regs[(env->exclusive_info >> 8) & 0xf];
645426f5abcSPaul Brook     switch (size) {
646426f5abcSPaul Brook     case 0:
647426f5abcSPaul Brook         segv = put_user_u8(val, addr);
648426f5abcSPaul Brook         break;
649426f5abcSPaul Brook     case 1:
650426f5abcSPaul Brook         segv = put_user_u16(val, addr);
651426f5abcSPaul Brook         break;
652426f5abcSPaul Brook     case 2:
653426f5abcSPaul Brook     case 3:
654426f5abcSPaul Brook         segv = put_user_u32(val, addr);
655426f5abcSPaul Brook         break;
656426f5abcSPaul Brook     }
657426f5abcSPaul Brook     if (segv) {
658426f5abcSPaul Brook         env->cp15.c6_data = addr;
659426f5abcSPaul Brook         goto done;
660426f5abcSPaul Brook     }
661426f5abcSPaul Brook     if (size == 3) {
662426f5abcSPaul Brook         val = env->regs[(env->exclusive_info >> 12) & 0xf];
6632c9adbdaSPeter Maydell         segv = put_user_u32(val, addr + 4);
664426f5abcSPaul Brook         if (segv) {
665426f5abcSPaul Brook             env->cp15.c6_data = addr + 4;
666426f5abcSPaul Brook             goto done;
667426f5abcSPaul Brook         }
668426f5abcSPaul Brook     }
669426f5abcSPaul Brook     rc = 0;
670426f5abcSPaul Brook fail:
671725b8a69SPaul Brook     env->regs[15] += 4;
672426f5abcSPaul Brook     env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
673426f5abcSPaul Brook done:
674426f5abcSPaul Brook     end_exclusive();
675426f5abcSPaul Brook     return segv;
676426f5abcSPaul Brook }
677426f5abcSPaul Brook 
678b346ff46Sbellard void cpu_loop(CPUARMState *env)
679b346ff46Sbellard {
680b346ff46Sbellard     int trapnr;
681b346ff46Sbellard     unsigned int n, insn;
682c227f099SAnthony Liguori     target_siginfo_t info;
683b5ff1b31Sbellard     uint32_t addr;
684b346ff46Sbellard 
685b346ff46Sbellard     for(;;) {
686d5975363Spbrook         cpu_exec_start(env);
687b346ff46Sbellard         trapnr = cpu_arm_exec(env);
688d5975363Spbrook         cpu_exec_end(env);
689b346ff46Sbellard         switch(trapnr) {
690b346ff46Sbellard         case EXCP_UDEF:
691c6981055Sbellard             {
692c6981055Sbellard                 TaskState *ts = env->opaque;
693c6981055Sbellard                 uint32_t opcode;
6946d9a42beSaurel32                 int rc;
695c6981055Sbellard 
696c6981055Sbellard                 /* we handle the FPU emulation here, as Linux */
697c6981055Sbellard                 /* we get the opcode */
6982f619698Sbellard                 /* FIXME - what to do if get_user() fails? */
6992f619698Sbellard                 get_user_u32(opcode, env->regs[15]);
700c6981055Sbellard 
7016d9a42beSaurel32                 rc = EmulateAll(opcode, &ts->fpa, env);
7026d9a42beSaurel32                 if (rc == 0) { /* illegal instruction */
703b346ff46Sbellard                     info.si_signo = SIGILL;
704b346ff46Sbellard                     info.si_errno = 0;
705b346ff46Sbellard                     info.si_code = TARGET_ILL_ILLOPN;
706b346ff46Sbellard                     info._sifields._sigfault._addr = env->regs[15];
707624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
7086d9a42beSaurel32                 } else if (rc < 0) { /* FP exception */
7096d9a42beSaurel32                     int arm_fpe=0;
7106d9a42beSaurel32 
7116d9a42beSaurel32                     /* translate softfloat flags to FPSR flags */
7126d9a42beSaurel32                     if (-rc & float_flag_invalid)
7136d9a42beSaurel32                       arm_fpe |= BIT_IOC;
7146d9a42beSaurel32                     if (-rc & float_flag_divbyzero)
7156d9a42beSaurel32                       arm_fpe |= BIT_DZC;
7166d9a42beSaurel32                     if (-rc & float_flag_overflow)
7176d9a42beSaurel32                       arm_fpe |= BIT_OFC;
7186d9a42beSaurel32                     if (-rc & float_flag_underflow)
7196d9a42beSaurel32                       arm_fpe |= BIT_UFC;
7206d9a42beSaurel32                     if (-rc & float_flag_inexact)
7216d9a42beSaurel32                       arm_fpe |= BIT_IXC;
7226d9a42beSaurel32 
7236d9a42beSaurel32                     FPSR fpsr = ts->fpa.fpsr;
7246d9a42beSaurel32                     //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
7256d9a42beSaurel32 
7266d9a42beSaurel32                     if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
7276d9a42beSaurel32                       info.si_signo = SIGFPE;
7286d9a42beSaurel32                       info.si_errno = 0;
7296d9a42beSaurel32 
7306d9a42beSaurel32                       /* ordered by priority, least first */
7316d9a42beSaurel32                       if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
7326d9a42beSaurel32                       if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
7336d9a42beSaurel32                       if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
7346d9a42beSaurel32                       if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
7356d9a42beSaurel32                       if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
7366d9a42beSaurel32 
7376d9a42beSaurel32                       info._sifields._sigfault._addr = env->regs[15];
738624f7979Spbrook                       queue_signal(env, info.si_signo, &info);
739c6981055Sbellard                     } else {
7406d9a42beSaurel32                       env->regs[15] += 4;
7416d9a42beSaurel32                     }
7426d9a42beSaurel32 
7436d9a42beSaurel32                     /* accumulate unenabled exceptions */
7446d9a42beSaurel32                     if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
7456d9a42beSaurel32                       fpsr |= BIT_IXC;
7466d9a42beSaurel32                     if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
7476d9a42beSaurel32                       fpsr |= BIT_UFC;
7486d9a42beSaurel32                     if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
7496d9a42beSaurel32                       fpsr |= BIT_OFC;
7506d9a42beSaurel32                     if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
7516d9a42beSaurel32                       fpsr |= BIT_DZC;
7526d9a42beSaurel32                     if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
7536d9a42beSaurel32                       fpsr |= BIT_IOC;
7546d9a42beSaurel32                     ts->fpa.fpsr=fpsr;
7556d9a42beSaurel32                 } else { /* everything OK */
756c6981055Sbellard                     /* increment PC */
757c6981055Sbellard                     env->regs[15] += 4;
758c6981055Sbellard                 }
759c6981055Sbellard             }
760b346ff46Sbellard             break;
761b346ff46Sbellard         case EXCP_SWI:
76206c949e6Spbrook         case EXCP_BKPT:
763b346ff46Sbellard             {
764ce4defa0Spbrook                 env->eabi = 1;
765b346ff46Sbellard                 /* system call */
76606c949e6Spbrook                 if (trapnr == EXCP_BKPT) {
76706c949e6Spbrook                     if (env->thumb) {
7682f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
7692f619698Sbellard                         get_user_u16(insn, env->regs[15]);
77006c949e6Spbrook                         n = insn & 0xff;
77106c949e6Spbrook                         env->regs[15] += 2;
77206c949e6Spbrook                     } else {
7732f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
7742f619698Sbellard                         get_user_u32(insn, env->regs[15]);
77506c949e6Spbrook                         n = (insn & 0xf) | ((insn >> 4) & 0xff0);
77606c949e6Spbrook                         env->regs[15] += 4;
77706c949e6Spbrook                     }
77806c949e6Spbrook                 } else {
779192c7bd9Sbellard                     if (env->thumb) {
7802f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
7812f619698Sbellard                         get_user_u16(insn, env->regs[15] - 2);
782192c7bd9Sbellard                         n = insn & 0xff;
783192c7bd9Sbellard                     } else {
7842f619698Sbellard                         /* FIXME - what to do if get_user() fails? */
7852f619698Sbellard                         get_user_u32(insn, env->regs[15] - 4);
786b346ff46Sbellard                         n = insn & 0xffffff;
787192c7bd9Sbellard                     }
78806c949e6Spbrook                 }
789192c7bd9Sbellard 
7906f1f31c0Sbellard                 if (n == ARM_NR_cacheflush) {
791dcfd14b3SBlue Swirl                     /* nop */
792a4f81979Sbellard                 } else if (n == ARM_NR_semihosting
793a4f81979Sbellard                            || n == ARM_NR_thumb_semihosting) {
794a4f81979Sbellard                     env->regs[0] = do_arm_semihosting (env);
795ce4defa0Spbrook                 } else if (n == 0 || n >= ARM_SYSCALL_BASE
796192c7bd9Sbellard                            || (env->thumb && n == ARM_THUMB_SYSCALL)) {
797b346ff46Sbellard                     /* linux syscall */
798ce4defa0Spbrook                     if (env->thumb || n == 0) {
799192c7bd9Sbellard                         n = env->regs[7];
800192c7bd9Sbellard                     } else {
801b346ff46Sbellard                         n -= ARM_SYSCALL_BASE;
802ce4defa0Spbrook                         env->eabi = 0;
803192c7bd9Sbellard                     }
804fbb4a2e3Spbrook                     if ( n > ARM_NR_BASE) {
805fbb4a2e3Spbrook                         switch (n) {
806fbb4a2e3Spbrook                         case ARM_NR_cacheflush:
807dcfd14b3SBlue Swirl                             /* nop */
808fbb4a2e3Spbrook                             break;
809fbb4a2e3Spbrook                         case ARM_NR_set_tls:
810fbb4a2e3Spbrook                             cpu_set_tls(env, env->regs[0]);
811fbb4a2e3Spbrook                             env->regs[0] = 0;
812fbb4a2e3Spbrook                             break;
813fbb4a2e3Spbrook                         default:
814fbb4a2e3Spbrook                             gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
815fbb4a2e3Spbrook                                      n);
816fbb4a2e3Spbrook                             env->regs[0] = -TARGET_ENOSYS;
817fbb4a2e3Spbrook                             break;
818fbb4a2e3Spbrook                         }
819fbb4a2e3Spbrook                     } else {
820b346ff46Sbellard                         env->regs[0] = do_syscall(env,
821b346ff46Sbellard                                                   n,
822b346ff46Sbellard                                                   env->regs[0],
823b346ff46Sbellard                                                   env->regs[1],
824b346ff46Sbellard                                                   env->regs[2],
825b346ff46Sbellard                                                   env->regs[3],
826b346ff46Sbellard                                                   env->regs[4],
8275945cfcbSPeter Maydell                                                   env->regs[5],
8285945cfcbSPeter Maydell                                                   0, 0);
829fbb4a2e3Spbrook                     }
830b346ff46Sbellard                 } else {
831b346ff46Sbellard                     goto error;
832b346ff46Sbellard                 }
833b346ff46Sbellard             }
834b346ff46Sbellard             break;
83543fff238Sbellard         case EXCP_INTERRUPT:
83643fff238Sbellard             /* just indicate that signals should be handled asap */
83743fff238Sbellard             break;
83868016c62Sbellard         case EXCP_PREFETCH_ABORT:
839eae473c1Sbalrog             addr = env->cp15.c6_insn;
840b5ff1b31Sbellard             goto do_segv;
84168016c62Sbellard         case EXCP_DATA_ABORT:
842eae473c1Sbalrog             addr = env->cp15.c6_data;
843b5ff1b31Sbellard         do_segv:
84468016c62Sbellard             {
84568016c62Sbellard                 info.si_signo = SIGSEGV;
84668016c62Sbellard                 info.si_errno = 0;
84768016c62Sbellard                 /* XXX: check env->error_code */
84868016c62Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
849b5ff1b31Sbellard                 info._sifields._sigfault._addr = addr;
850624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
85168016c62Sbellard             }
85268016c62Sbellard             break;
8531fddef4bSbellard         case EXCP_DEBUG:
8541fddef4bSbellard             {
8551fddef4bSbellard                 int sig;
8561fddef4bSbellard 
8571fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
8581fddef4bSbellard                 if (sig)
8591fddef4bSbellard                   {
8601fddef4bSbellard                     info.si_signo = sig;
8611fddef4bSbellard                     info.si_errno = 0;
8621fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
863624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
8641fddef4bSbellard                   }
8651fddef4bSbellard             }
8661fddef4bSbellard             break;
867fbb4a2e3Spbrook         case EXCP_KERNEL_TRAP:
868fbb4a2e3Spbrook             if (do_kernel_trap(env))
869fbb4a2e3Spbrook               goto error;
870fbb4a2e3Spbrook             break;
871426f5abcSPaul Brook         case EXCP_STREX:
872426f5abcSPaul Brook             if (do_strex(env)) {
873426f5abcSPaul Brook                 addr = env->cp15.c6_data;
874426f5abcSPaul Brook                 goto do_segv;
875426f5abcSPaul Brook             }
876e9273455SPaul Brook             break;
877b346ff46Sbellard         default:
878b346ff46Sbellard         error:
879b346ff46Sbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
880b346ff46Sbellard                     trapnr);
8817fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
882b346ff46Sbellard             abort();
883b346ff46Sbellard         }
884b346ff46Sbellard         process_pending_signals(env);
885b346ff46Sbellard     }
886b346ff46Sbellard }
887b346ff46Sbellard 
888b346ff46Sbellard #endif
8891b6b029eSbellard 
890d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32
891d2fbca94SGuan Xuetao 
892d2fbca94SGuan Xuetao void cpu_loop(CPUState *env)
893d2fbca94SGuan Xuetao {
894d2fbca94SGuan Xuetao     int trapnr;
895d2fbca94SGuan Xuetao     unsigned int n, insn;
896d2fbca94SGuan Xuetao     target_siginfo_t info;
897d2fbca94SGuan Xuetao 
898d2fbca94SGuan Xuetao     for (;;) {
899d2fbca94SGuan Xuetao         cpu_exec_start(env);
900d2fbca94SGuan Xuetao         trapnr = uc32_cpu_exec(env);
901d2fbca94SGuan Xuetao         cpu_exec_end(env);
902d2fbca94SGuan Xuetao         switch (trapnr) {
903d2fbca94SGuan Xuetao         case UC32_EXCP_PRIV:
904d2fbca94SGuan Xuetao             {
905d2fbca94SGuan Xuetao                 /* system call */
906d2fbca94SGuan Xuetao                 get_user_u32(insn, env->regs[31] - 4);
907d2fbca94SGuan Xuetao                 n = insn & 0xffffff;
908d2fbca94SGuan Xuetao 
909d2fbca94SGuan Xuetao                 if (n >= UC32_SYSCALL_BASE) {
910d2fbca94SGuan Xuetao                     /* linux syscall */
911d2fbca94SGuan Xuetao                     n -= UC32_SYSCALL_BASE;
912d2fbca94SGuan Xuetao                     if (n == UC32_SYSCALL_NR_set_tls) {
913d2fbca94SGuan Xuetao                             cpu_set_tls(env, env->regs[0]);
914d2fbca94SGuan Xuetao                             env->regs[0] = 0;
915d2fbca94SGuan Xuetao                     } else {
916d2fbca94SGuan Xuetao                         env->regs[0] = do_syscall(env,
917d2fbca94SGuan Xuetao                                                   n,
918d2fbca94SGuan Xuetao                                                   env->regs[0],
919d2fbca94SGuan Xuetao                                                   env->regs[1],
920d2fbca94SGuan Xuetao                                                   env->regs[2],
921d2fbca94SGuan Xuetao                                                   env->regs[3],
922d2fbca94SGuan Xuetao                                                   env->regs[4],
9235945cfcbSPeter Maydell                                                   env->regs[5],
9245945cfcbSPeter Maydell                                                   0, 0);
925d2fbca94SGuan Xuetao                     }
926d2fbca94SGuan Xuetao                 } else {
927d2fbca94SGuan Xuetao                     goto error;
928d2fbca94SGuan Xuetao                 }
929d2fbca94SGuan Xuetao             }
930d2fbca94SGuan Xuetao             break;
931d2fbca94SGuan Xuetao         case UC32_EXCP_TRAP:
932d2fbca94SGuan Xuetao             info.si_signo = SIGSEGV;
933d2fbca94SGuan Xuetao             info.si_errno = 0;
934d2fbca94SGuan Xuetao             /* XXX: check env->error_code */
935d2fbca94SGuan Xuetao             info.si_code = TARGET_SEGV_MAPERR;
936d2fbca94SGuan Xuetao             info._sifields._sigfault._addr = env->cp0.c4_faultaddr;
937d2fbca94SGuan Xuetao             queue_signal(env, info.si_signo, &info);
938d2fbca94SGuan Xuetao             break;
939d2fbca94SGuan Xuetao         case EXCP_INTERRUPT:
940d2fbca94SGuan Xuetao             /* just indicate that signals should be handled asap */
941d2fbca94SGuan Xuetao             break;
942d2fbca94SGuan Xuetao         case EXCP_DEBUG:
943d2fbca94SGuan Xuetao             {
944d2fbca94SGuan Xuetao                 int sig;
945d2fbca94SGuan Xuetao 
946d2fbca94SGuan Xuetao                 sig = gdb_handlesig(env, TARGET_SIGTRAP);
947d2fbca94SGuan Xuetao                 if (sig) {
948d2fbca94SGuan Xuetao                     info.si_signo = sig;
949d2fbca94SGuan Xuetao                     info.si_errno = 0;
950d2fbca94SGuan Xuetao                     info.si_code = TARGET_TRAP_BRKPT;
951d2fbca94SGuan Xuetao                     queue_signal(env, info.si_signo, &info);
952d2fbca94SGuan Xuetao                 }
953d2fbca94SGuan Xuetao             }
954d2fbca94SGuan Xuetao             break;
955d2fbca94SGuan Xuetao         default:
956d2fbca94SGuan Xuetao             goto error;
957d2fbca94SGuan Xuetao         }
958d2fbca94SGuan Xuetao         process_pending_signals(env);
959d2fbca94SGuan Xuetao     }
960d2fbca94SGuan Xuetao 
961d2fbca94SGuan Xuetao error:
962d2fbca94SGuan Xuetao     fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
963d2fbca94SGuan Xuetao     cpu_dump_state(env, stderr, fprintf, 0);
964d2fbca94SGuan Xuetao     abort();
965d2fbca94SGuan Xuetao }
966d2fbca94SGuan Xuetao #endif
967d2fbca94SGuan Xuetao 
96893ac68bcSbellard #ifdef TARGET_SPARC
969ed23fbd9Sblueswir1 #define SPARC64_STACK_BIAS 2047
97093ac68bcSbellard 
971060366c5Sbellard //#define DEBUG_WIN
972060366c5Sbellard 
9732623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info
9742623cbafSbellard    can be found at http://www.sics.se/~psm/sparcstack.html */
975060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
976060366c5Sbellard {
9771a14026eSblueswir1     index = (index + cwp * 16) % (16 * env->nwindows);
978060366c5Sbellard     /* wrap handling : if cwp is on the last window, then we use the
979060366c5Sbellard        registers 'after' the end */
9801a14026eSblueswir1     if (index < 8 && env->cwp == env->nwindows - 1)
9811a14026eSblueswir1         index += 16 * env->nwindows;
982060366c5Sbellard     return index;
983060366c5Sbellard }
984060366c5Sbellard 
9852623cbafSbellard /* save the register window 'cwp1' */
9862623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1)
987060366c5Sbellard {
9882623cbafSbellard     unsigned int i;
989992f48a0Sblueswir1     abi_ulong sp_ptr;
990060366c5Sbellard 
99153a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
992ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
993ed23fbd9Sblueswir1     if (sp_ptr & 3)
994ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
995ed23fbd9Sblueswir1 #endif
996060366c5Sbellard #if defined(DEBUG_WIN)
9972daf0284Sblueswir1     printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
9982daf0284Sblueswir1            sp_ptr, cwp1);
999060366c5Sbellard #endif
10002623cbafSbellard     for(i = 0; i < 16; i++) {
10012f619698Sbellard         /* FIXME - what to do if put_user() fails? */
10022f619698Sbellard         put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1003992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
10042623cbafSbellard     }
1005060366c5Sbellard }
1006060366c5Sbellard 
1007060366c5Sbellard static void save_window(CPUSPARCState *env)
1008060366c5Sbellard {
10095ef54116Sbellard #ifndef TARGET_SPARC64
10102623cbafSbellard     unsigned int new_wim;
10111a14026eSblueswir1     new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
10121a14026eSblueswir1         ((1LL << env->nwindows) - 1);
10131a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10142623cbafSbellard     env->wim = new_wim;
10155ef54116Sbellard #else
10161a14026eSblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10175ef54116Sbellard     env->cansave++;
10185ef54116Sbellard     env->canrestore--;
10195ef54116Sbellard #endif
1020060366c5Sbellard }
1021060366c5Sbellard 
1022060366c5Sbellard static void restore_window(CPUSPARCState *env)
1023060366c5Sbellard {
1024eda52953Sblueswir1 #ifndef TARGET_SPARC64
1025eda52953Sblueswir1     unsigned int new_wim;
1026eda52953Sblueswir1 #endif
1027eda52953Sblueswir1     unsigned int i, cwp1;
1028992f48a0Sblueswir1     abi_ulong sp_ptr;
1029060366c5Sbellard 
1030eda52953Sblueswir1 #ifndef TARGET_SPARC64
10311a14026eSblueswir1     new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
10321a14026eSblueswir1         ((1LL << env->nwindows) - 1);
1033eda52953Sblueswir1 #endif
1034060366c5Sbellard 
1035060366c5Sbellard     /* restore the invalid window */
10361a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
103753a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
1038ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64
1039ed23fbd9Sblueswir1     if (sp_ptr & 3)
1040ed23fbd9Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
1041ed23fbd9Sblueswir1 #endif
1042060366c5Sbellard #if defined(DEBUG_WIN)
10432daf0284Sblueswir1     printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
10442daf0284Sblueswir1            sp_ptr, cwp1);
1045060366c5Sbellard #endif
10462623cbafSbellard     for(i = 0; i < 16; i++) {
10472f619698Sbellard         /* FIXME - what to do if get_user() fails? */
10482f619698Sbellard         get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
1049992f48a0Sblueswir1         sp_ptr += sizeof(abi_ulong);
10502623cbafSbellard     }
10515ef54116Sbellard #ifdef TARGET_SPARC64
10525ef54116Sbellard     env->canrestore++;
10531a14026eSblueswir1     if (env->cleanwin < env->nwindows - 1)
10545ef54116Sbellard         env->cleanwin++;
10555ef54116Sbellard     env->cansave--;
1056eda52953Sblueswir1 #else
1057eda52953Sblueswir1     env->wim = new_wim;
10585ef54116Sbellard #endif
1059060366c5Sbellard }
1060060366c5Sbellard 
1061060366c5Sbellard static void flush_windows(CPUSPARCState *env)
1062060366c5Sbellard {
1063060366c5Sbellard     int offset, cwp1;
10642623cbafSbellard 
10652623cbafSbellard     offset = 1;
1066060366c5Sbellard     for(;;) {
1067060366c5Sbellard         /* if restore would invoke restore_window(), then we can stop */
10681a14026eSblueswir1         cwp1 = cpu_cwp_inc(env, env->cwp + offset);
1069eda52953Sblueswir1 #ifndef TARGET_SPARC64
1070060366c5Sbellard         if (env->wim & (1 << cwp1))
1071060366c5Sbellard             break;
1072eda52953Sblueswir1 #else
1073eda52953Sblueswir1         if (env->canrestore == 0)
1074eda52953Sblueswir1             break;
1075eda52953Sblueswir1         env->cansave++;
1076eda52953Sblueswir1         env->canrestore--;
1077eda52953Sblueswir1 #endif
10782623cbafSbellard         save_window_offset(env, cwp1);
1079060366c5Sbellard         offset++;
1080060366c5Sbellard     }
10811a14026eSblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
1082eda52953Sblueswir1 #ifndef TARGET_SPARC64
1083eda52953Sblueswir1     /* set wim so that restore will reload the registers */
10842623cbafSbellard     env->wim = 1 << cwp1;
1085eda52953Sblueswir1 #endif
10862623cbafSbellard #if defined(DEBUG_WIN)
10872623cbafSbellard     printf("flush_windows: nb=%d\n", offset - 1);
108880a9d035Sbellard #endif
10892623cbafSbellard }
1090060366c5Sbellard 
109193ac68bcSbellard void cpu_loop (CPUSPARCState *env)
109293ac68bcSbellard {
10932cc20260SRichard Henderson     int trapnr;
10942cc20260SRichard Henderson     abi_long ret;
1095c227f099SAnthony Liguori     target_siginfo_t info;
109693ac68bcSbellard 
109793ac68bcSbellard     while (1) {
109893ac68bcSbellard         trapnr = cpu_sparc_exec (env);
109993ac68bcSbellard 
110093ac68bcSbellard         switch (trapnr) {
11015ef54116Sbellard #ifndef TARGET_SPARC64
1102060366c5Sbellard         case 0x88:
1103060366c5Sbellard         case 0x90:
11045ef54116Sbellard #else
1105cb33da57Sblueswir1         case 0x110:
11065ef54116Sbellard         case 0x16d:
11075ef54116Sbellard #endif
1108060366c5Sbellard             ret = do_syscall (env, env->gregs[1],
1109060366c5Sbellard                               env->regwptr[0], env->regwptr[1],
1110060366c5Sbellard                               env->regwptr[2], env->regwptr[3],
11115945cfcbSPeter Maydell                               env->regwptr[4], env->regwptr[5],
11125945cfcbSPeter Maydell                               0, 0);
11132cc20260SRichard Henderson             if ((abi_ulong)ret >= (abi_ulong)(-515)) {
1114992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
111527908725Sbellard                 env->xcc |= PSR_CARRY;
111627908725Sbellard #else
111793ac68bcSbellard                 env->psr |= PSR_CARRY;
111827908725Sbellard #endif
1119060366c5Sbellard                 ret = -ret;
1120060366c5Sbellard             } else {
1121992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
112227908725Sbellard                 env->xcc &= ~PSR_CARRY;
112327908725Sbellard #else
1124060366c5Sbellard                 env->psr &= ~PSR_CARRY;
112527908725Sbellard #endif
1126060366c5Sbellard             }
1127060366c5Sbellard             env->regwptr[0] = ret;
1128060366c5Sbellard             /* next instruction */
1129060366c5Sbellard             env->pc = env->npc;
1130060366c5Sbellard             env->npc = env->npc + 4;
1131060366c5Sbellard             break;
1132060366c5Sbellard         case 0x83: /* flush windows */
1133992f48a0Sblueswir1 #ifdef TARGET_ABI32
1134992f48a0Sblueswir1         case 0x103:
1135992f48a0Sblueswir1 #endif
11362623cbafSbellard             flush_windows(env);
1137060366c5Sbellard             /* next instruction */
1138060366c5Sbellard             env->pc = env->npc;
1139060366c5Sbellard             env->npc = env->npc + 4;
1140060366c5Sbellard             break;
11413475187dSbellard #ifndef TARGET_SPARC64
1142060366c5Sbellard         case TT_WIN_OVF: /* window overflow */
1143060366c5Sbellard             save_window(env);
1144060366c5Sbellard             break;
1145060366c5Sbellard         case TT_WIN_UNF: /* window underflow */
1146060366c5Sbellard             restore_window(env);
114793ac68bcSbellard             break;
114861ff6f58Sbellard         case TT_TFAULT:
114961ff6f58Sbellard         case TT_DFAULT:
115061ff6f58Sbellard             {
115159f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
115261ff6f58Sbellard                 info.si_errno = 0;
115361ff6f58Sbellard                 /* XXX: check env->error_code */
115461ff6f58Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
115561ff6f58Sbellard                 info._sifields._sigfault._addr = env->mmuregs[4];
1156624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
115761ff6f58Sbellard             }
115861ff6f58Sbellard             break;
11593475187dSbellard #else
11605ef54116Sbellard         case TT_SPILL: /* window overflow */
11615ef54116Sbellard             save_window(env);
11625ef54116Sbellard             break;
11635ef54116Sbellard         case TT_FILL: /* window underflow */
11645ef54116Sbellard             restore_window(env);
11655ef54116Sbellard             break;
11667f84a729Sblueswir1         case TT_TFAULT:
11677f84a729Sblueswir1         case TT_DFAULT:
11687f84a729Sblueswir1             {
116959f7182fSRichard Henderson                 info.si_signo = TARGET_SIGSEGV;
11707f84a729Sblueswir1                 info.si_errno = 0;
11717f84a729Sblueswir1                 /* XXX: check env->error_code */
11727f84a729Sblueswir1                 info.si_code = TARGET_SEGV_MAPERR;
11737f84a729Sblueswir1                 if (trapnr == TT_DFAULT)
11747f84a729Sblueswir1                     info._sifields._sigfault._addr = env->dmmuregs[4];
11757f84a729Sblueswir1                 else
11768194f35aSIgor Kovalenko                     info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
1177624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
11787f84a729Sblueswir1             }
11797f84a729Sblueswir1             break;
118027524dc3Sbellard #ifndef TARGET_ABI32
11815bfb56b2Sblueswir1         case 0x16e:
11825bfb56b2Sblueswir1             flush_windows(env);
11835bfb56b2Sblueswir1             sparc64_get_context(env);
11845bfb56b2Sblueswir1             break;
11855bfb56b2Sblueswir1         case 0x16f:
11865bfb56b2Sblueswir1             flush_windows(env);
11875bfb56b2Sblueswir1             sparc64_set_context(env);
11885bfb56b2Sblueswir1             break;
11893475187dSbellard #endif
119027524dc3Sbellard #endif
119148dc41ebSbellard         case EXCP_INTERRUPT:
119248dc41ebSbellard             /* just indicate that signals should be handled asap */
1193e80cfcfcSbellard             break;
119475f22e4eSRichard Henderson         case TT_ILL_INSN:
119575f22e4eSRichard Henderson             {
119675f22e4eSRichard Henderson                 info.si_signo = TARGET_SIGILL;
119775f22e4eSRichard Henderson                 info.si_errno = 0;
119875f22e4eSRichard Henderson                 info.si_code = TARGET_ILL_ILLOPC;
119975f22e4eSRichard Henderson                 info._sifields._sigfault._addr = env->pc;
120075f22e4eSRichard Henderson                 queue_signal(env, info.si_signo, &info);
120175f22e4eSRichard Henderson             }
120275f22e4eSRichard Henderson             break;
12031fddef4bSbellard         case EXCP_DEBUG:
12041fddef4bSbellard             {
12051fddef4bSbellard                 int sig;
12061fddef4bSbellard 
12071fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
12081fddef4bSbellard                 if (sig)
12091fddef4bSbellard                   {
12101fddef4bSbellard                     info.si_signo = sig;
12111fddef4bSbellard                     info.si_errno = 0;
12121fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
1213624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
12141fddef4bSbellard                   }
12151fddef4bSbellard             }
12161fddef4bSbellard             break;
121793ac68bcSbellard         default:
1218060366c5Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
12197fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
122093ac68bcSbellard             exit (1);
122193ac68bcSbellard         }
122293ac68bcSbellard         process_pending_signals (env);
122393ac68bcSbellard     }
122493ac68bcSbellard }
122593ac68bcSbellard 
122693ac68bcSbellard #endif
122793ac68bcSbellard 
122867867308Sbellard #ifdef TARGET_PPC
12299fddaa0cSbellard static inline uint64_t cpu_ppc_get_tb (CPUState *env)
12309fddaa0cSbellard {
12319fddaa0cSbellard     /* TO FIX */
12329fddaa0cSbellard     return 0;
12339fddaa0cSbellard }
12349fddaa0cSbellard 
1235e3ea6529SAlexander Graf uint64_t cpu_ppc_load_tbl (CPUState *env)
12369fddaa0cSbellard {
1237e3ea6529SAlexander Graf     return cpu_ppc_get_tb(env);
12389fddaa0cSbellard }
12399fddaa0cSbellard 
12409fddaa0cSbellard uint32_t cpu_ppc_load_tbu (CPUState *env)
12419fddaa0cSbellard {
12429fddaa0cSbellard     return cpu_ppc_get_tb(env) >> 32;
12439fddaa0cSbellard }
12449fddaa0cSbellard 
1245b711de95SAurelien Jarno uint64_t cpu_ppc_load_atbl (CPUState *env)
12469fddaa0cSbellard {
1247b711de95SAurelien Jarno     return cpu_ppc_get_tb(env);
12489fddaa0cSbellard }
12499fddaa0cSbellard 
1250a062e36cSj_mayer uint32_t cpu_ppc_load_atbu (CPUState *env)
12519fddaa0cSbellard {
1252a062e36cSj_mayer     return cpu_ppc_get_tb(env) >> 32;
12539fddaa0cSbellard }
12549fddaa0cSbellard 
125576a66253Sj_mayer uint32_t cpu_ppc601_load_rtcu (CPUState *env)
125676a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_load_tbu") ));
125776a66253Sj_mayer 
125876a66253Sj_mayer uint32_t cpu_ppc601_load_rtcl (CPUState *env)
12599fddaa0cSbellard {
126076a66253Sj_mayer     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
12619fddaa0cSbellard }
12629fddaa0cSbellard 
1263a750fc0bSj_mayer /* XXX: to be fixed */
126473b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
1265a750fc0bSj_mayer {
1266a750fc0bSj_mayer     return -1;
1267a750fc0bSj_mayer }
1268a750fc0bSj_mayer 
126973b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
1270a750fc0bSj_mayer {
1271a750fc0bSj_mayer     return -1;
1272a750fc0bSj_mayer }
1273a750fc0bSj_mayer 
1274001faf32SBlue Swirl #define EXCP_DUMP(env, fmt, ...)                                        \
1275e1833e1fSj_mayer do {                                                                    \
1276001faf32SBlue Swirl     fprintf(stderr, fmt , ## __VA_ARGS__);                              \
1277e1833e1fSj_mayer     cpu_dump_state(env, stderr, fprintf, 0);                            \
1278001faf32SBlue Swirl     qemu_log(fmt, ## __VA_ARGS__);                                      \
1279430c7ec7Smalc     if (logfile)                                                        \
128093fcfe39Saliguori         log_cpu_state(env, 0);                                          \
1281e1833e1fSj_mayer } while (0)
1282e1833e1fSj_mayer 
128356f066bbSNathan Froyd static int do_store_exclusive(CPUPPCState *env)
128456f066bbSNathan Froyd {
128556f066bbSNathan Froyd     target_ulong addr;
128656f066bbSNathan Froyd     target_ulong page_addr;
128756f066bbSNathan Froyd     target_ulong val;
128856f066bbSNathan Froyd     int flags;
128956f066bbSNathan Froyd     int segv = 0;
129056f066bbSNathan Froyd 
129156f066bbSNathan Froyd     addr = env->reserve_ea;
129256f066bbSNathan Froyd     page_addr = addr & TARGET_PAGE_MASK;
129356f066bbSNathan Froyd     start_exclusive();
129456f066bbSNathan Froyd     mmap_lock();
129556f066bbSNathan Froyd     flags = page_get_flags(page_addr);
129656f066bbSNathan Froyd     if ((flags & PAGE_READ) == 0) {
129756f066bbSNathan Froyd         segv = 1;
129856f066bbSNathan Froyd     } else {
129956f066bbSNathan Froyd         int reg = env->reserve_info & 0x1f;
130056f066bbSNathan Froyd         int size = (env->reserve_info >> 5) & 0xf;
130156f066bbSNathan Froyd         int stored = 0;
130256f066bbSNathan Froyd 
130356f066bbSNathan Froyd         if (addr == env->reserve_addr) {
130456f066bbSNathan Froyd             switch (size) {
130556f066bbSNathan Froyd             case 1: segv = get_user_u8(val, addr); break;
130656f066bbSNathan Froyd             case 2: segv = get_user_u16(val, addr); break;
130756f066bbSNathan Froyd             case 4: segv = get_user_u32(val, addr); break;
130856f066bbSNathan Froyd #if defined(TARGET_PPC64)
130956f066bbSNathan Froyd             case 8: segv = get_user_u64(val, addr); break;
131056f066bbSNathan Froyd #endif
131156f066bbSNathan Froyd             default: abort();
131256f066bbSNathan Froyd             }
131356f066bbSNathan Froyd             if (!segv && val == env->reserve_val) {
131456f066bbSNathan Froyd                 val = env->gpr[reg];
131556f066bbSNathan Froyd                 switch (size) {
131656f066bbSNathan Froyd                 case 1: segv = put_user_u8(val, addr); break;
131756f066bbSNathan Froyd                 case 2: segv = put_user_u16(val, addr); break;
131856f066bbSNathan Froyd                 case 4: segv = put_user_u32(val, addr); break;
131956f066bbSNathan Froyd #if defined(TARGET_PPC64)
132056f066bbSNathan Froyd                 case 8: segv = put_user_u64(val, addr); break;
132156f066bbSNathan Froyd #endif
132256f066bbSNathan Froyd                 default: abort();
132356f066bbSNathan Froyd                 }
132456f066bbSNathan Froyd                 if (!segv) {
132556f066bbSNathan Froyd                     stored = 1;
132656f066bbSNathan Froyd                 }
132756f066bbSNathan Froyd             }
132856f066bbSNathan Froyd         }
132956f066bbSNathan Froyd         env->crf[0] = (stored << 1) | xer_so;
133056f066bbSNathan Froyd         env->reserve_addr = (target_ulong)-1;
133156f066bbSNathan Froyd     }
133256f066bbSNathan Froyd     if (!segv) {
133356f066bbSNathan Froyd         env->nip += 4;
133456f066bbSNathan Froyd     }
133556f066bbSNathan Froyd     mmap_unlock();
133656f066bbSNathan Froyd     end_exclusive();
133756f066bbSNathan Froyd     return segv;
133856f066bbSNathan Froyd }
133956f066bbSNathan Froyd 
134067867308Sbellard void cpu_loop(CPUPPCState *env)
134167867308Sbellard {
1342c227f099SAnthony Liguori     target_siginfo_t info;
134361190b14Sbellard     int trapnr;
13449e0e2f96SRichard Henderson     target_ulong ret;
134567867308Sbellard 
134667867308Sbellard     for(;;) {
134756f066bbSNathan Froyd         cpu_exec_start(env);
134867867308Sbellard         trapnr = cpu_ppc_exec(env);
134956f066bbSNathan Froyd         cpu_exec_end(env);
135067867308Sbellard         switch(trapnr) {
1351e1833e1fSj_mayer         case POWERPC_EXCP_NONE:
1352e1833e1fSj_mayer             /* Just go on */
135367867308Sbellard             break;
1354e1833e1fSj_mayer         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
1355e1833e1fSj_mayer             cpu_abort(env, "Critical interrupt while in user mode. "
1356e1833e1fSj_mayer                       "Aborting\n");
1357e1833e1fSj_mayer             break;
1358e1833e1fSj_mayer         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
1359e1833e1fSj_mayer             cpu_abort(env, "Machine check exception while in user mode. "
1360e1833e1fSj_mayer                       "Aborting\n");
1361e1833e1fSj_mayer             break;
1362e1833e1fSj_mayer         case POWERPC_EXCP_DSI:      /* Data storage exception                */
136390e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
1364e1833e1fSj_mayer                       env->spr[SPR_DAR]);
1365e1833e1fSj_mayer             /* XXX: check this. Seems bugged */
1366e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1367e1833e1fSj_mayer             case 0x40000000:
1368e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1369e1833e1fSj_mayer                 info.si_errno = 0;
1370e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1371e1833e1fSj_mayer                 break;
1372e1833e1fSj_mayer             case 0x04000000:
1373e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1374e1833e1fSj_mayer                 info.si_errno = 0;
1375e1833e1fSj_mayer                 info.si_code = TARGET_ILL_ILLADR;
1376e1833e1fSj_mayer                 break;
1377e1833e1fSj_mayer             case 0x08000000:
1378e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1379e1833e1fSj_mayer                 info.si_errno = 0;
1380e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_ACCERR;
1381e1833e1fSj_mayer                 break;
1382e1833e1fSj_mayer             default:
1383e1833e1fSj_mayer                 /* Let's send a regular segfault... */
1384e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
1385e1833e1fSj_mayer                           env->error_code);
1386e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1387e1833e1fSj_mayer                 info.si_errno = 0;
1388e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1389e1833e1fSj_mayer                 break;
1390e1833e1fSj_mayer             }
1391e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip;
1392624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1393e1833e1fSj_mayer             break;
1394e1833e1fSj_mayer         case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
139590e189ecSBlue Swirl             EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
139690e189ecSBlue Swirl                       "\n", env->spr[SPR_SRR0]);
1397e1833e1fSj_mayer             /* XXX: check this */
1398e1833e1fSj_mayer             switch (env->error_code & 0xFF000000) {
1399e1833e1fSj_mayer             case 0x40000000:
1400e1833e1fSj_mayer                 info.si_signo = TARGET_SIGSEGV;
1401e1833e1fSj_mayer             info.si_errno = 0;
1402e1833e1fSj_mayer                 info.si_code = TARGET_SEGV_MAPERR;
1403e1833e1fSj_mayer                 break;
1404e1833e1fSj_mayer             case 0x10000000:
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 - 4;
1420624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1421e1833e1fSj_mayer             break;
1422e1833e1fSj_mayer         case POWERPC_EXCP_EXTERNAL: /* External input                        */
1423e1833e1fSj_mayer             cpu_abort(env, "External interrupt while in user mode. "
1424e1833e1fSj_mayer                       "Aborting\n");
1425e1833e1fSj_mayer             break;
1426e1833e1fSj_mayer         case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
1427e1833e1fSj_mayer             EXCP_DUMP(env, "Unaligned memory access\n");
1428e1833e1fSj_mayer             /* XXX: check this */
1429e1833e1fSj_mayer             info.si_signo = TARGET_SIGBUS;
1430e1833e1fSj_mayer             info.si_errno = 0;
1431e1833e1fSj_mayer             info.si_code = TARGET_BUS_ADRALN;
1432e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1433624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1434e1833e1fSj_mayer             break;
1435e1833e1fSj_mayer         case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
1436e1833e1fSj_mayer             /* XXX: check this */
1437e1833e1fSj_mayer             switch (env->error_code & ~0xF) {
1438e1833e1fSj_mayer             case POWERPC_EXCP_FP:
1439e1833e1fSj_mayer                 EXCP_DUMP(env, "Floating point program exception\n");
1440e1833e1fSj_mayer                 info.si_signo = TARGET_SIGFPE;
1441e1833e1fSj_mayer                 info.si_errno = 0;
1442e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1443e1833e1fSj_mayer                 case POWERPC_EXCP_FP_OX:
1444e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTOVF;
1445e1833e1fSj_mayer                     break;
1446e1833e1fSj_mayer                 case POWERPC_EXCP_FP_UX:
1447e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTUND;
1448e1833e1fSj_mayer                     break;
1449e1833e1fSj_mayer                 case POWERPC_EXCP_FP_ZX:
1450e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXZDZ:
1451e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTDIV;
1452e1833e1fSj_mayer                     break;
1453e1833e1fSj_mayer                 case POWERPC_EXCP_FP_XX:
1454e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTRES;
1455e1833e1fSj_mayer                     break;
1456e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSOFT:
1457e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTINV;
1458e1833e1fSj_mayer                     break;
14597c58044cSj_mayer                 case POWERPC_EXCP_FP_VXSNAN:
1460e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXISI:
1461e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIDI:
1462e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXIMZ:
1463e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXVC:
1464e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXSQRT:
1465e1833e1fSj_mayer                 case POWERPC_EXCP_FP_VXCVI:
1466e1833e1fSj_mayer                     info.si_code = TARGET_FPE_FLTSUB;
1467e1833e1fSj_mayer                     break;
1468e1833e1fSj_mayer                 default:
1469e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
1470e1833e1fSj_mayer                               env->error_code);
1471e1833e1fSj_mayer                     break;
1472e1833e1fSj_mayer                 }
1473e1833e1fSj_mayer                 break;
1474e1833e1fSj_mayer             case POWERPC_EXCP_INVAL:
1475e1833e1fSj_mayer                 EXCP_DUMP(env, "Invalid instruction\n");
1476e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1477e1833e1fSj_mayer                 info.si_errno = 0;
1478e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1479e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_INVAL:
1480e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPC;
1481e1833e1fSj_mayer                     break;
1482e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_LSWX:
1483e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLOPN;
1484e1833e1fSj_mayer                     break;
1485e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_SPR:
1486e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1487e1833e1fSj_mayer                     break;
1488e1833e1fSj_mayer                 case POWERPC_EXCP_INVAL_FP:
1489e1833e1fSj_mayer                     info.si_code = TARGET_ILL_COPROC;
1490e1833e1fSj_mayer                     break;
1491e1833e1fSj_mayer                 default:
1492e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
1493e1833e1fSj_mayer                               env->error_code & 0xF);
1494e1833e1fSj_mayer                     info.si_code = TARGET_ILL_ILLADR;
1495e1833e1fSj_mayer                     break;
1496e1833e1fSj_mayer                 }
1497e1833e1fSj_mayer                 break;
1498e1833e1fSj_mayer             case POWERPC_EXCP_PRIV:
1499e1833e1fSj_mayer                 EXCP_DUMP(env, "Privilege violation\n");
1500e1833e1fSj_mayer                 info.si_signo = TARGET_SIGILL;
1501e1833e1fSj_mayer                 info.si_errno = 0;
1502e1833e1fSj_mayer                 switch (env->error_code & 0xF) {
1503e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_OPC:
1504e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1505e1833e1fSj_mayer                     break;
1506e1833e1fSj_mayer                 case POWERPC_EXCP_PRIV_REG:
1507e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVREG;
1508e1833e1fSj_mayer                     break;
1509e1833e1fSj_mayer                 default:
1510e1833e1fSj_mayer                     EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
1511e1833e1fSj_mayer                               env->error_code & 0xF);
1512e1833e1fSj_mayer                     info.si_code = TARGET_ILL_PRVOPC;
1513e1833e1fSj_mayer                     break;
1514e1833e1fSj_mayer                 }
1515e1833e1fSj_mayer                 break;
1516e1833e1fSj_mayer             case POWERPC_EXCP_TRAP:
1517e1833e1fSj_mayer                 cpu_abort(env, "Tried to call a TRAP\n");
1518e1833e1fSj_mayer                 break;
1519e1833e1fSj_mayer             default:
1520e1833e1fSj_mayer                 /* Should not happen ! */
1521e1833e1fSj_mayer                 cpu_abort(env, "Unknown program exception (%02x)\n",
1522e1833e1fSj_mayer                           env->error_code);
1523e1833e1fSj_mayer                 break;
1524e1833e1fSj_mayer             }
1525e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1526624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1527e1833e1fSj_mayer             break;
1528e1833e1fSj_mayer         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
1529e1833e1fSj_mayer             EXCP_DUMP(env, "No floating point allowed\n");
1530e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1531e1833e1fSj_mayer             info.si_errno = 0;
1532e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1533e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1534624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1535e1833e1fSj_mayer             break;
1536e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
1537e1833e1fSj_mayer             cpu_abort(env, "Syscall exception while in user mode. "
1538e1833e1fSj_mayer                       "Aborting\n");
1539e1833e1fSj_mayer             break;
1540e1833e1fSj_mayer         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
1541e1833e1fSj_mayer             EXCP_DUMP(env, "No APU instruction allowed\n");
1542e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1543e1833e1fSj_mayer             info.si_errno = 0;
1544e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1545e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1546624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1547e1833e1fSj_mayer             break;
1548e1833e1fSj_mayer         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
1549e1833e1fSj_mayer             cpu_abort(env, "Decrementer interrupt while in user mode. "
1550e1833e1fSj_mayer                       "Aborting\n");
1551e1833e1fSj_mayer             break;
1552e1833e1fSj_mayer         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
1553e1833e1fSj_mayer             cpu_abort(env, "Fix interval timer interrupt while in user mode. "
1554e1833e1fSj_mayer                       "Aborting\n");
1555e1833e1fSj_mayer             break;
1556e1833e1fSj_mayer         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
1557e1833e1fSj_mayer             cpu_abort(env, "Watchdog timer interrupt while in user mode. "
1558e1833e1fSj_mayer                       "Aborting\n");
1559e1833e1fSj_mayer             break;
1560e1833e1fSj_mayer         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
1561e1833e1fSj_mayer             cpu_abort(env, "Data TLB exception while in user mode. "
1562e1833e1fSj_mayer                       "Aborting\n");
1563e1833e1fSj_mayer             break;
1564e1833e1fSj_mayer         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
1565e1833e1fSj_mayer             cpu_abort(env, "Instruction TLB exception while in user mode. "
1566e1833e1fSj_mayer                       "Aborting\n");
1567e1833e1fSj_mayer             break;
1568e1833e1fSj_mayer         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
1569e1833e1fSj_mayer             EXCP_DUMP(env, "No SPE/floating-point 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_EFPDI:    /* Embedded floating-point data IRQ      */
1577e1833e1fSj_mayer             cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
1578e1833e1fSj_mayer             break;
1579e1833e1fSj_mayer         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
1580e1833e1fSj_mayer             cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
1581e1833e1fSj_mayer             break;
1582e1833e1fSj_mayer         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
1583e1833e1fSj_mayer             cpu_abort(env, "Performance monitor exception not handled\n");
1584e1833e1fSj_mayer             break;
1585e1833e1fSj_mayer         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
1586e1833e1fSj_mayer             cpu_abort(env, "Doorbell interrupt while in user mode. "
1587e1833e1fSj_mayer                        "Aborting\n");
1588e1833e1fSj_mayer             break;
1589e1833e1fSj_mayer         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
1590e1833e1fSj_mayer             cpu_abort(env, "Doorbell critical interrupt while in user mode. "
1591e1833e1fSj_mayer                       "Aborting\n");
1592e1833e1fSj_mayer             break;
1593e1833e1fSj_mayer         case POWERPC_EXCP_RESET:    /* System reset exception                */
1594e1833e1fSj_mayer             cpu_abort(env, "Reset interrupt while in user mode. "
1595e1833e1fSj_mayer                       "Aborting\n");
1596e1833e1fSj_mayer             break;
1597e1833e1fSj_mayer         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
1598e1833e1fSj_mayer             cpu_abort(env, "Data segment exception while in user mode. "
1599e1833e1fSj_mayer                       "Aborting\n");
1600e1833e1fSj_mayer             break;
1601e1833e1fSj_mayer         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
1602e1833e1fSj_mayer             cpu_abort(env, "Instruction segment exception "
1603e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1604e1833e1fSj_mayer             break;
1605e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1606e1833e1fSj_mayer         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
1607e1833e1fSj_mayer             cpu_abort(env, "Hypervisor decrementer interrupt "
1608e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1609e1833e1fSj_mayer             break;
1610e1833e1fSj_mayer         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
1611e1833e1fSj_mayer             /* Nothing to do:
1612e1833e1fSj_mayer              * we use this exception to emulate step-by-step execution mode.
1613e1833e1fSj_mayer              */
1614e1833e1fSj_mayer             break;
1615e85e7c6eSj_mayer         /* PowerPC 64 with hypervisor mode support */
1616e1833e1fSj_mayer         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
1617e1833e1fSj_mayer             cpu_abort(env, "Hypervisor data storage exception "
1618e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1619e1833e1fSj_mayer             break;
1620e1833e1fSj_mayer         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
1621e1833e1fSj_mayer             cpu_abort(env, "Hypervisor instruction storage exception "
1622e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1623e1833e1fSj_mayer             break;
1624e1833e1fSj_mayer         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
1625e1833e1fSj_mayer             cpu_abort(env, "Hypervisor data segment exception "
1626e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1627e1833e1fSj_mayer             break;
1628e1833e1fSj_mayer         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
1629e1833e1fSj_mayer             cpu_abort(env, "Hypervisor instruction segment exception "
1630e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1631e1833e1fSj_mayer             break;
1632e1833e1fSj_mayer         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
1633e1833e1fSj_mayer             EXCP_DUMP(env, "No Altivec instructions allowed\n");
1634e1833e1fSj_mayer             info.si_signo = TARGET_SIGILL;
1635e1833e1fSj_mayer             info.si_errno = 0;
1636e1833e1fSj_mayer             info.si_code = TARGET_ILL_COPROC;
1637e1833e1fSj_mayer             info._sifields._sigfault._addr = env->nip - 4;
1638624f7979Spbrook             queue_signal(env, info.si_signo, &info);
1639e1833e1fSj_mayer             break;
1640e1833e1fSj_mayer         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
1641*b4916d7bSDong Xu Wang             cpu_abort(env, "Programmable interval timer interrupt "
1642e1833e1fSj_mayer                       "while in user mode. Aborting\n");
1643e1833e1fSj_mayer             break;
1644e1833e1fSj_mayer         case POWERPC_EXCP_IO:       /* IO error exception                    */
1645e1833e1fSj_mayer             cpu_abort(env, "IO error exception while in user mode. "
1646e1833e1fSj_mayer                       "Aborting\n");
1647e1833e1fSj_mayer             break;
1648e1833e1fSj_mayer         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
1649e1833e1fSj_mayer             cpu_abort(env, "Run mode exception while in user mode. "
1650e1833e1fSj_mayer                       "Aborting\n");
1651e1833e1fSj_mayer             break;
1652e1833e1fSj_mayer         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
1653e1833e1fSj_mayer             cpu_abort(env, "Emulation trap exception not handled\n");
1654e1833e1fSj_mayer             break;
1655e1833e1fSj_mayer         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
1656e1833e1fSj_mayer             cpu_abort(env, "Instruction fetch TLB exception "
1657e1833e1fSj_mayer                       "while in user-mode. Aborting");
1658e1833e1fSj_mayer             break;
1659e1833e1fSj_mayer         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
1660e1833e1fSj_mayer             cpu_abort(env, "Data load TLB exception while in user-mode. "
1661e1833e1fSj_mayer                       "Aborting");
1662e1833e1fSj_mayer             break;
1663e1833e1fSj_mayer         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
1664e1833e1fSj_mayer             cpu_abort(env, "Data store TLB exception while in user-mode. "
1665e1833e1fSj_mayer                       "Aborting");
1666e1833e1fSj_mayer             break;
1667e1833e1fSj_mayer         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
1668e1833e1fSj_mayer             cpu_abort(env, "Floating-point assist exception not handled\n");
1669e1833e1fSj_mayer             break;
1670e1833e1fSj_mayer         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
1671e1833e1fSj_mayer             cpu_abort(env, "Instruction address breakpoint exception "
1672e1833e1fSj_mayer                       "not handled\n");
1673e1833e1fSj_mayer             break;
1674e1833e1fSj_mayer         case POWERPC_EXCP_SMI:      /* System management interrupt           */
1675e1833e1fSj_mayer             cpu_abort(env, "System management interrupt while in user mode. "
1676e1833e1fSj_mayer                       "Aborting\n");
1677e1833e1fSj_mayer             break;
1678e1833e1fSj_mayer         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
1679e1833e1fSj_mayer             cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
1680e1833e1fSj_mayer                       "Aborting\n");
1681e1833e1fSj_mayer             break;
1682e1833e1fSj_mayer         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
1683e1833e1fSj_mayer             cpu_abort(env, "Performance monitor exception not handled\n");
1684e1833e1fSj_mayer             break;
1685e1833e1fSj_mayer         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
1686e1833e1fSj_mayer             cpu_abort(env, "Vector assist exception not handled\n");
1687e1833e1fSj_mayer             break;
1688e1833e1fSj_mayer         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
1689e1833e1fSj_mayer             cpu_abort(env, "Soft patch exception not handled\n");
1690e1833e1fSj_mayer             break;
1691e1833e1fSj_mayer         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
1692e1833e1fSj_mayer             cpu_abort(env, "Maintenance exception while in user mode. "
1693e1833e1fSj_mayer                       "Aborting\n");
1694e1833e1fSj_mayer             break;
1695e1833e1fSj_mayer         case POWERPC_EXCP_STOP:     /* stop translation                      */
1696e1833e1fSj_mayer             /* We did invalidate the instruction cache. Go on */
1697e1833e1fSj_mayer             break;
1698e1833e1fSj_mayer         case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
1699e1833e1fSj_mayer             /* We just stopped because of a branch. Go on */
1700e1833e1fSj_mayer             break;
1701e1833e1fSj_mayer         case POWERPC_EXCP_SYSCALL_USER:
1702e1833e1fSj_mayer             /* system call in user-mode emulation */
170367867308Sbellard             /* WARNING:
170467867308Sbellard              * PPC ABI uses overflow flag in cr0 to signal an error
170567867308Sbellard              * in syscalls.
170667867308Sbellard              */
170767867308Sbellard             env->crf[0] &= ~0x1;
170867867308Sbellard             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
170967867308Sbellard                              env->gpr[5], env->gpr[6], env->gpr[7],
17105945cfcbSPeter Maydell                              env->gpr[8], 0, 0);
17119e0e2f96SRichard Henderson             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
1712bcd4933aSNathan Froyd                 /* Returning from a successful sigreturn syscall.
1713bcd4933aSNathan Froyd                    Avoid corrupting register state.  */
1714bcd4933aSNathan Froyd                 break;
1715bcd4933aSNathan Froyd             }
17169e0e2f96SRichard Henderson             if (ret > (target_ulong)(-515)) {
171767867308Sbellard                 env->crf[0] |= 0x1;
171867867308Sbellard                 ret = -ret;
171967867308Sbellard             }
172067867308Sbellard             env->gpr[3] = ret;
172161190b14Sbellard             break;
172256f066bbSNathan Froyd         case POWERPC_EXCP_STCX:
172356f066bbSNathan Froyd             if (do_store_exclusive(env)) {
172456f066bbSNathan Froyd                 info.si_signo = TARGET_SIGSEGV;
172556f066bbSNathan Froyd                 info.si_errno = 0;
172656f066bbSNathan Froyd                 info.si_code = TARGET_SEGV_MAPERR;
172756f066bbSNathan Froyd                 info._sifields._sigfault._addr = env->nip;
172856f066bbSNathan Froyd                 queue_signal(env, info.si_signo, &info);
172956f066bbSNathan Froyd             }
173056f066bbSNathan Froyd             break;
173171f75756Saurel32         case EXCP_DEBUG:
173271f75756Saurel32             {
173371f75756Saurel32                 int sig;
173471f75756Saurel32 
173571f75756Saurel32                 sig = gdb_handlesig(env, TARGET_SIGTRAP);
173671f75756Saurel32                 if (sig) {
173771f75756Saurel32                     info.si_signo = sig;
173871f75756Saurel32                     info.si_errno = 0;
173971f75756Saurel32                     info.si_code = TARGET_TRAP_BRKPT;
174071f75756Saurel32                     queue_signal(env, info.si_signo, &info);
174171f75756Saurel32                   }
174271f75756Saurel32             }
174371f75756Saurel32             break;
174456ba31ffSj_mayer         case EXCP_INTERRUPT:
174556ba31ffSj_mayer             /* just indicate that signals should be handled asap */
174656ba31ffSj_mayer             break;
174761190b14Sbellard         default:
1748e1833e1fSj_mayer             cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
174967867308Sbellard             break;
175067867308Sbellard         }
175167867308Sbellard         process_pending_signals(env);
175267867308Sbellard     }
175367867308Sbellard }
175467867308Sbellard #endif
175567867308Sbellard 
1756048f6b4dSbellard #ifdef TARGET_MIPS
1757048f6b4dSbellard 
1758048f6b4dSbellard #define MIPS_SYS(name, args) args,
1759048f6b4dSbellard 
1760048f6b4dSbellard static const uint8_t mips_syscall_args[] = {
176129fb0f25SAn-Cheng Huang 	MIPS_SYS(sys_syscall	, 8)	/* 4000 */
1762048f6b4dSbellard 	MIPS_SYS(sys_exit	, 1)
1763048f6b4dSbellard 	MIPS_SYS(sys_fork	, 0)
1764048f6b4dSbellard 	MIPS_SYS(sys_read	, 3)
1765048f6b4dSbellard 	MIPS_SYS(sys_write	, 3)
1766048f6b4dSbellard 	MIPS_SYS(sys_open	, 3)	/* 4005 */
1767048f6b4dSbellard 	MIPS_SYS(sys_close	, 1)
1768048f6b4dSbellard 	MIPS_SYS(sys_waitpid	, 3)
1769048f6b4dSbellard 	MIPS_SYS(sys_creat	, 2)
1770048f6b4dSbellard 	MIPS_SYS(sys_link	, 2)
1771048f6b4dSbellard 	MIPS_SYS(sys_unlink	, 1)	/* 4010 */
1772048f6b4dSbellard 	MIPS_SYS(sys_execve	, 0)
1773048f6b4dSbellard 	MIPS_SYS(sys_chdir	, 1)
1774048f6b4dSbellard 	MIPS_SYS(sys_time	, 1)
1775048f6b4dSbellard 	MIPS_SYS(sys_mknod	, 3)
1776048f6b4dSbellard 	MIPS_SYS(sys_chmod	, 2)	/* 4015 */
1777048f6b4dSbellard 	MIPS_SYS(sys_lchown	, 3)
1778048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1779048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_stat */
1780048f6b4dSbellard 	MIPS_SYS(sys_lseek	, 3)
1781048f6b4dSbellard 	MIPS_SYS(sys_getpid	, 0)	/* 4020 */
1782048f6b4dSbellard 	MIPS_SYS(sys_mount	, 5)
1783048f6b4dSbellard 	MIPS_SYS(sys_oldumount	, 1)
1784048f6b4dSbellard 	MIPS_SYS(sys_setuid	, 1)
1785048f6b4dSbellard 	MIPS_SYS(sys_getuid	, 0)
1786048f6b4dSbellard 	MIPS_SYS(sys_stime	, 1)	/* 4025 */
1787048f6b4dSbellard 	MIPS_SYS(sys_ptrace	, 4)
1788048f6b4dSbellard 	MIPS_SYS(sys_alarm	, 1)
1789048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_fstat */
1790048f6b4dSbellard 	MIPS_SYS(sys_pause	, 0)
1791048f6b4dSbellard 	MIPS_SYS(sys_utime	, 2)	/* 4030 */
1792048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1793048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1794048f6b4dSbellard 	MIPS_SYS(sys_access	, 2)
1795048f6b4dSbellard 	MIPS_SYS(sys_nice	, 1)
1796048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4035 */
1797048f6b4dSbellard 	MIPS_SYS(sys_sync	, 0)
1798048f6b4dSbellard 	MIPS_SYS(sys_kill	, 2)
1799048f6b4dSbellard 	MIPS_SYS(sys_rename	, 2)
1800048f6b4dSbellard 	MIPS_SYS(sys_mkdir	, 2)
1801048f6b4dSbellard 	MIPS_SYS(sys_rmdir	, 1)	/* 4040 */
1802048f6b4dSbellard 	MIPS_SYS(sys_dup		, 1)
1803048f6b4dSbellard 	MIPS_SYS(sys_pipe	, 0)
1804048f6b4dSbellard 	MIPS_SYS(sys_times	, 1)
1805048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1806048f6b4dSbellard 	MIPS_SYS(sys_brk		, 1)	/* 4045 */
1807048f6b4dSbellard 	MIPS_SYS(sys_setgid	, 1)
1808048f6b4dSbellard 	MIPS_SYS(sys_getgid	, 0)
1809048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was signal(2) */
1810048f6b4dSbellard 	MIPS_SYS(sys_geteuid	, 0)
1811048f6b4dSbellard 	MIPS_SYS(sys_getegid	, 0)	/* 4050 */
1812048f6b4dSbellard 	MIPS_SYS(sys_acct	, 0)
1813048f6b4dSbellard 	MIPS_SYS(sys_umount	, 2)
1814048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1815048f6b4dSbellard 	MIPS_SYS(sys_ioctl	, 3)
1816048f6b4dSbellard 	MIPS_SYS(sys_fcntl	, 3)	/* 4055 */
1817048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 2)
1818048f6b4dSbellard 	MIPS_SYS(sys_setpgid	, 2)
1819048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1820048f6b4dSbellard 	MIPS_SYS(sys_olduname	, 1)
1821048f6b4dSbellard 	MIPS_SYS(sys_umask	, 1)	/* 4060 */
1822048f6b4dSbellard 	MIPS_SYS(sys_chroot	, 1)
1823048f6b4dSbellard 	MIPS_SYS(sys_ustat	, 2)
1824048f6b4dSbellard 	MIPS_SYS(sys_dup2	, 2)
1825048f6b4dSbellard 	MIPS_SYS(sys_getppid	, 0)
1826048f6b4dSbellard 	MIPS_SYS(sys_getpgrp	, 0)	/* 4065 */
1827048f6b4dSbellard 	MIPS_SYS(sys_setsid	, 0)
1828048f6b4dSbellard 	MIPS_SYS(sys_sigaction	, 3)
1829048f6b4dSbellard 	MIPS_SYS(sys_sgetmask	, 0)
1830048f6b4dSbellard 	MIPS_SYS(sys_ssetmask	, 1)
1831048f6b4dSbellard 	MIPS_SYS(sys_setreuid	, 2)	/* 4070 */
1832048f6b4dSbellard 	MIPS_SYS(sys_setregid	, 2)
1833048f6b4dSbellard 	MIPS_SYS(sys_sigsuspend	, 0)
1834048f6b4dSbellard 	MIPS_SYS(sys_sigpending	, 1)
1835048f6b4dSbellard 	MIPS_SYS(sys_sethostname	, 2)
1836048f6b4dSbellard 	MIPS_SYS(sys_setrlimit	, 2)	/* 4075 */
1837048f6b4dSbellard 	MIPS_SYS(sys_getrlimit	, 2)
1838048f6b4dSbellard 	MIPS_SYS(sys_getrusage	, 2)
1839048f6b4dSbellard 	MIPS_SYS(sys_gettimeofday, 2)
1840048f6b4dSbellard 	MIPS_SYS(sys_settimeofday, 2)
1841048f6b4dSbellard 	MIPS_SYS(sys_getgroups	, 2)	/* 4080 */
1842048f6b4dSbellard 	MIPS_SYS(sys_setgroups	, 2)
1843048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* old_select */
1844048f6b4dSbellard 	MIPS_SYS(sys_symlink	, 2)
1845048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_lstat */
1846048f6b4dSbellard 	MIPS_SYS(sys_readlink	, 3)	/* 4085 */
1847048f6b4dSbellard 	MIPS_SYS(sys_uselib	, 1)
1848048f6b4dSbellard 	MIPS_SYS(sys_swapon	, 2)
1849048f6b4dSbellard 	MIPS_SYS(sys_reboot	, 3)
1850048f6b4dSbellard 	MIPS_SYS(old_readdir	, 3)
1851048f6b4dSbellard 	MIPS_SYS(old_mmap	, 6)	/* 4090 */
1852048f6b4dSbellard 	MIPS_SYS(sys_munmap	, 2)
1853048f6b4dSbellard 	MIPS_SYS(sys_truncate	, 2)
1854048f6b4dSbellard 	MIPS_SYS(sys_ftruncate	, 2)
1855048f6b4dSbellard 	MIPS_SYS(sys_fchmod	, 2)
1856048f6b4dSbellard 	MIPS_SYS(sys_fchown	, 3)	/* 4095 */
1857048f6b4dSbellard 	MIPS_SYS(sys_getpriority	, 2)
1858048f6b4dSbellard 	MIPS_SYS(sys_setpriority	, 3)
1859048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1860048f6b4dSbellard 	MIPS_SYS(sys_statfs	, 2)
1861048f6b4dSbellard 	MIPS_SYS(sys_fstatfs	, 2)	/* 4100 */
1862048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was ioperm(2) */
1863048f6b4dSbellard 	MIPS_SYS(sys_socketcall	, 2)
1864048f6b4dSbellard 	MIPS_SYS(sys_syslog	, 3)
1865048f6b4dSbellard 	MIPS_SYS(sys_setitimer	, 3)
1866048f6b4dSbellard 	MIPS_SYS(sys_getitimer	, 2)	/* 4105 */
1867048f6b4dSbellard 	MIPS_SYS(sys_newstat	, 2)
1868048f6b4dSbellard 	MIPS_SYS(sys_newlstat	, 2)
1869048f6b4dSbellard 	MIPS_SYS(sys_newfstat	, 2)
1870048f6b4dSbellard 	MIPS_SYS(sys_uname	, 1)
1871048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4110 was iopl(2) */
1872048f6b4dSbellard 	MIPS_SYS(sys_vhangup	, 0)
1873048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_idle() */
1874048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_vm86 */
1875048f6b4dSbellard 	MIPS_SYS(sys_wait4	, 4)
1876048f6b4dSbellard 	MIPS_SYS(sys_swapoff	, 1)	/* 4115 */
1877048f6b4dSbellard 	MIPS_SYS(sys_sysinfo	, 1)
1878048f6b4dSbellard 	MIPS_SYS(sys_ipc		, 6)
1879048f6b4dSbellard 	MIPS_SYS(sys_fsync	, 1)
1880048f6b4dSbellard 	MIPS_SYS(sys_sigreturn	, 0)
188118113962SPaul Brook 	MIPS_SYS(sys_clone	, 6)	/* 4120 */
1882048f6b4dSbellard 	MIPS_SYS(sys_setdomainname, 2)
1883048f6b4dSbellard 	MIPS_SYS(sys_newuname	, 1)
1884048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_modify_ldt */
1885048f6b4dSbellard 	MIPS_SYS(sys_adjtimex	, 1)
1886048f6b4dSbellard 	MIPS_SYS(sys_mprotect	, 3)	/* 4125 */
1887048f6b4dSbellard 	MIPS_SYS(sys_sigprocmask	, 3)
1888048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was create_module */
1889048f6b4dSbellard 	MIPS_SYS(sys_init_module	, 5)
1890048f6b4dSbellard 	MIPS_SYS(sys_delete_module, 1)
1891048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4130	was get_kernel_syms */
1892048f6b4dSbellard 	MIPS_SYS(sys_quotactl	, 0)
1893048f6b4dSbellard 	MIPS_SYS(sys_getpgid	, 1)
1894048f6b4dSbellard 	MIPS_SYS(sys_fchdir	, 1)
1895048f6b4dSbellard 	MIPS_SYS(sys_bdflush	, 2)
1896048f6b4dSbellard 	MIPS_SYS(sys_sysfs	, 3)	/* 4135 */
1897048f6b4dSbellard 	MIPS_SYS(sys_personality	, 1)
1898048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* for afs_syscall */
1899048f6b4dSbellard 	MIPS_SYS(sys_setfsuid	, 1)
1900048f6b4dSbellard 	MIPS_SYS(sys_setfsgid	, 1)
1901048f6b4dSbellard 	MIPS_SYS(sys_llseek	, 5)	/* 4140 */
1902048f6b4dSbellard 	MIPS_SYS(sys_getdents	, 3)
1903048f6b4dSbellard 	MIPS_SYS(sys_select	, 5)
1904048f6b4dSbellard 	MIPS_SYS(sys_flock	, 2)
1905048f6b4dSbellard 	MIPS_SYS(sys_msync	, 3)
1906048f6b4dSbellard 	MIPS_SYS(sys_readv	, 3)	/* 4145 */
1907048f6b4dSbellard 	MIPS_SYS(sys_writev	, 3)
1908048f6b4dSbellard 	MIPS_SYS(sys_cacheflush	, 3)
1909048f6b4dSbellard 	MIPS_SYS(sys_cachectl	, 3)
1910048f6b4dSbellard 	MIPS_SYS(sys_sysmips	, 4)
1911048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4150 */
1912048f6b4dSbellard 	MIPS_SYS(sys_getsid	, 1)
1913048f6b4dSbellard 	MIPS_SYS(sys_fdatasync	, 0)
1914048f6b4dSbellard 	MIPS_SYS(sys_sysctl	, 1)
1915048f6b4dSbellard 	MIPS_SYS(sys_mlock	, 2)
1916048f6b4dSbellard 	MIPS_SYS(sys_munlock	, 2)	/* 4155 */
1917048f6b4dSbellard 	MIPS_SYS(sys_mlockall	, 1)
1918048f6b4dSbellard 	MIPS_SYS(sys_munlockall	, 0)
1919048f6b4dSbellard 	MIPS_SYS(sys_sched_setparam, 2)
1920048f6b4dSbellard 	MIPS_SYS(sys_sched_getparam, 2)
1921048f6b4dSbellard 	MIPS_SYS(sys_sched_setscheduler, 3)	/* 4160 */
1922048f6b4dSbellard 	MIPS_SYS(sys_sched_getscheduler, 1)
1923048f6b4dSbellard 	MIPS_SYS(sys_sched_yield	, 0)
1924048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_max, 1)
1925048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_min, 1)
1926048f6b4dSbellard 	MIPS_SYS(sys_sched_rr_get_interval, 2)	/* 4165 */
1927048f6b4dSbellard 	MIPS_SYS(sys_nanosleep,	2)
1928048f6b4dSbellard 	MIPS_SYS(sys_mremap	, 4)
1929048f6b4dSbellard 	MIPS_SYS(sys_accept	, 3)
1930048f6b4dSbellard 	MIPS_SYS(sys_bind	, 3)
1931048f6b4dSbellard 	MIPS_SYS(sys_connect	, 3)	/* 4170 */
1932048f6b4dSbellard 	MIPS_SYS(sys_getpeername	, 3)
1933048f6b4dSbellard 	MIPS_SYS(sys_getsockname	, 3)
1934048f6b4dSbellard 	MIPS_SYS(sys_getsockopt	, 5)
1935048f6b4dSbellard 	MIPS_SYS(sys_listen	, 2)
1936048f6b4dSbellard 	MIPS_SYS(sys_recv	, 4)	/* 4175 */
1937048f6b4dSbellard 	MIPS_SYS(sys_recvfrom	, 6)
1938048f6b4dSbellard 	MIPS_SYS(sys_recvmsg	, 3)
1939048f6b4dSbellard 	MIPS_SYS(sys_send	, 4)
1940048f6b4dSbellard 	MIPS_SYS(sys_sendmsg	, 3)
1941048f6b4dSbellard 	MIPS_SYS(sys_sendto	, 6)	/* 4180 */
1942048f6b4dSbellard 	MIPS_SYS(sys_setsockopt	, 5)
1943048f6b4dSbellard 	MIPS_SYS(sys_shutdown	, 2)
1944048f6b4dSbellard 	MIPS_SYS(sys_socket	, 3)
1945048f6b4dSbellard 	MIPS_SYS(sys_socketpair	, 4)
1946048f6b4dSbellard 	MIPS_SYS(sys_setresuid	, 3)	/* 4185 */
1947048f6b4dSbellard 	MIPS_SYS(sys_getresuid	, 3)
1948048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_query_module */
1949048f6b4dSbellard 	MIPS_SYS(sys_poll	, 3)
1950048f6b4dSbellard 	MIPS_SYS(sys_nfsservctl	, 3)
1951048f6b4dSbellard 	MIPS_SYS(sys_setresgid	, 3)	/* 4190 */
1952048f6b4dSbellard 	MIPS_SYS(sys_getresgid	, 3)
1953048f6b4dSbellard 	MIPS_SYS(sys_prctl	, 5)
1954048f6b4dSbellard 	MIPS_SYS(sys_rt_sigreturn, 0)
1955048f6b4dSbellard 	MIPS_SYS(sys_rt_sigaction, 4)
1956048f6b4dSbellard 	MIPS_SYS(sys_rt_sigprocmask, 4)	/* 4195 */
1957048f6b4dSbellard 	MIPS_SYS(sys_rt_sigpending, 2)
1958048f6b4dSbellard 	MIPS_SYS(sys_rt_sigtimedwait, 4)
1959048f6b4dSbellard 	MIPS_SYS(sys_rt_sigqueueinfo, 3)
1960048f6b4dSbellard 	MIPS_SYS(sys_rt_sigsuspend, 0)
1961048f6b4dSbellard 	MIPS_SYS(sys_pread64	, 6)	/* 4200 */
1962048f6b4dSbellard 	MIPS_SYS(sys_pwrite64	, 6)
1963048f6b4dSbellard 	MIPS_SYS(sys_chown	, 3)
1964048f6b4dSbellard 	MIPS_SYS(sys_getcwd	, 2)
1965048f6b4dSbellard 	MIPS_SYS(sys_capget	, 2)
1966048f6b4dSbellard 	MIPS_SYS(sys_capset	, 2)	/* 4205 */
1967053ebb27SWesley W. Terpstra 	MIPS_SYS(sys_sigaltstack	, 2)
1968048f6b4dSbellard 	MIPS_SYS(sys_sendfile	, 4)
1969048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1970048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1971048f6b4dSbellard 	MIPS_SYS(sys_mmap2	, 6)	/* 4210 */
1972048f6b4dSbellard 	MIPS_SYS(sys_truncate64	, 4)
1973048f6b4dSbellard 	MIPS_SYS(sys_ftruncate64	, 4)
1974048f6b4dSbellard 	MIPS_SYS(sys_stat64	, 2)
1975048f6b4dSbellard 	MIPS_SYS(sys_lstat64	, 2)
1976048f6b4dSbellard 	MIPS_SYS(sys_fstat64	, 2)	/* 4215 */
1977048f6b4dSbellard 	MIPS_SYS(sys_pivot_root	, 2)
1978048f6b4dSbellard 	MIPS_SYS(sys_mincore	, 3)
1979048f6b4dSbellard 	MIPS_SYS(sys_madvise	, 3)
1980048f6b4dSbellard 	MIPS_SYS(sys_getdents64	, 3)
1981048f6b4dSbellard 	MIPS_SYS(sys_fcntl64	, 3)	/* 4220 */
1982048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1983048f6b4dSbellard 	MIPS_SYS(sys_gettid	, 0)
1984048f6b4dSbellard 	MIPS_SYS(sys_readahead	, 5)
1985048f6b4dSbellard 	MIPS_SYS(sys_setxattr	, 5)
1986048f6b4dSbellard 	MIPS_SYS(sys_lsetxattr	, 5)	/* 4225 */
1987048f6b4dSbellard 	MIPS_SYS(sys_fsetxattr	, 5)
1988048f6b4dSbellard 	MIPS_SYS(sys_getxattr	, 4)
1989048f6b4dSbellard 	MIPS_SYS(sys_lgetxattr	, 4)
1990048f6b4dSbellard 	MIPS_SYS(sys_fgetxattr	, 4)
1991048f6b4dSbellard 	MIPS_SYS(sys_listxattr	, 3)	/* 4230 */
1992048f6b4dSbellard 	MIPS_SYS(sys_llistxattr	, 3)
1993048f6b4dSbellard 	MIPS_SYS(sys_flistxattr	, 3)
1994048f6b4dSbellard 	MIPS_SYS(sys_removexattr	, 2)
1995048f6b4dSbellard 	MIPS_SYS(sys_lremovexattr, 2)
1996048f6b4dSbellard 	MIPS_SYS(sys_fremovexattr, 2)	/* 4235 */
1997048f6b4dSbellard 	MIPS_SYS(sys_tkill	, 2)
1998048f6b4dSbellard 	MIPS_SYS(sys_sendfile64	, 5)
1999048f6b4dSbellard 	MIPS_SYS(sys_futex	, 2)
2000048f6b4dSbellard 	MIPS_SYS(sys_sched_setaffinity, 3)
2001048f6b4dSbellard 	MIPS_SYS(sys_sched_getaffinity, 3)	/* 4240 */
2002048f6b4dSbellard 	MIPS_SYS(sys_io_setup	, 2)
2003048f6b4dSbellard 	MIPS_SYS(sys_io_destroy	, 1)
2004048f6b4dSbellard 	MIPS_SYS(sys_io_getevents, 5)
2005048f6b4dSbellard 	MIPS_SYS(sys_io_submit	, 3)
2006048f6b4dSbellard 	MIPS_SYS(sys_io_cancel	, 3)	/* 4245 */
2007048f6b4dSbellard 	MIPS_SYS(sys_exit_group	, 1)
2008048f6b4dSbellard 	MIPS_SYS(sys_lookup_dcookie, 3)
2009048f6b4dSbellard 	MIPS_SYS(sys_epoll_create, 1)
2010048f6b4dSbellard 	MIPS_SYS(sys_epoll_ctl	, 4)
2011048f6b4dSbellard 	MIPS_SYS(sys_epoll_wait	, 3)	/* 4250 */
2012048f6b4dSbellard 	MIPS_SYS(sys_remap_file_pages, 5)
2013048f6b4dSbellard 	MIPS_SYS(sys_set_tid_address, 1)
2014048f6b4dSbellard 	MIPS_SYS(sys_restart_syscall, 0)
2015048f6b4dSbellard 	MIPS_SYS(sys_fadvise64_64, 7)
2016048f6b4dSbellard 	MIPS_SYS(sys_statfs64	, 3)	/* 4255 */
2017048f6b4dSbellard 	MIPS_SYS(sys_fstatfs64	, 2)
2018048f6b4dSbellard 	MIPS_SYS(sys_timer_create, 3)
2019048f6b4dSbellard 	MIPS_SYS(sys_timer_settime, 4)
2020048f6b4dSbellard 	MIPS_SYS(sys_timer_gettime, 2)
2021048f6b4dSbellard 	MIPS_SYS(sys_timer_getoverrun, 1)	/* 4260 */
2022048f6b4dSbellard 	MIPS_SYS(sys_timer_delete, 1)
2023048f6b4dSbellard 	MIPS_SYS(sys_clock_settime, 2)
2024048f6b4dSbellard 	MIPS_SYS(sys_clock_gettime, 2)
2025048f6b4dSbellard 	MIPS_SYS(sys_clock_getres, 2)
2026048f6b4dSbellard 	MIPS_SYS(sys_clock_nanosleep, 4)	/* 4265 */
2027048f6b4dSbellard 	MIPS_SYS(sys_tgkill	, 3)
2028048f6b4dSbellard 	MIPS_SYS(sys_utimes	, 2)
2029048f6b4dSbellard 	MIPS_SYS(sys_mbind	, 4)
2030048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_get_mempolicy */
2031048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4270 sys_set_mempolicy */
2032048f6b4dSbellard 	MIPS_SYS(sys_mq_open	, 4)
2033048f6b4dSbellard 	MIPS_SYS(sys_mq_unlink	, 1)
2034048f6b4dSbellard 	MIPS_SYS(sys_mq_timedsend, 5)
2035048f6b4dSbellard 	MIPS_SYS(sys_mq_timedreceive, 5)
2036048f6b4dSbellard 	MIPS_SYS(sys_mq_notify	, 2)	/* 4275 */
2037048f6b4dSbellard 	MIPS_SYS(sys_mq_getsetattr, 3)
2038048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_vserver */
2039048f6b4dSbellard 	MIPS_SYS(sys_waitid	, 4)
2040048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
2041048f6b4dSbellard 	MIPS_SYS(sys_add_key	, 5)
2042048f6b4dSbellard 	MIPS_SYS(sys_request_key, 4)
2043048f6b4dSbellard 	MIPS_SYS(sys_keyctl	, 5)
20446f5b89a0Sths 	MIPS_SYS(sys_set_thread_area, 1)
2045388bb21aSths 	MIPS_SYS(sys_inotify_init, 0)
2046388bb21aSths 	MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
2047388bb21aSths 	MIPS_SYS(sys_inotify_rm_watch, 2)
2048388bb21aSths 	MIPS_SYS(sys_migrate_pages, 4)
2049388bb21aSths 	MIPS_SYS(sys_openat, 4)
2050388bb21aSths 	MIPS_SYS(sys_mkdirat, 3)
2051388bb21aSths 	MIPS_SYS(sys_mknodat, 4)	/* 4290 */
2052388bb21aSths 	MIPS_SYS(sys_fchownat, 5)
2053388bb21aSths 	MIPS_SYS(sys_futimesat, 3)
2054388bb21aSths 	MIPS_SYS(sys_fstatat64, 4)
2055388bb21aSths 	MIPS_SYS(sys_unlinkat, 3)
2056388bb21aSths 	MIPS_SYS(sys_renameat, 4)	/* 4295 */
2057388bb21aSths 	MIPS_SYS(sys_linkat, 5)
2058388bb21aSths 	MIPS_SYS(sys_symlinkat, 3)
2059388bb21aSths 	MIPS_SYS(sys_readlinkat, 4)
2060388bb21aSths 	MIPS_SYS(sys_fchmodat, 3)
2061388bb21aSths 	MIPS_SYS(sys_faccessat, 3)	/* 4300 */
2062388bb21aSths 	MIPS_SYS(sys_pselect6, 6)
2063388bb21aSths 	MIPS_SYS(sys_ppoll, 5)
2064388bb21aSths 	MIPS_SYS(sys_unshare, 1)
2065388bb21aSths 	MIPS_SYS(sys_splice, 4)
2066388bb21aSths 	MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
2067388bb21aSths 	MIPS_SYS(sys_tee, 4)
2068388bb21aSths 	MIPS_SYS(sys_vmsplice, 4)
2069388bb21aSths 	MIPS_SYS(sys_move_pages, 6)
2070388bb21aSths 	MIPS_SYS(sys_set_robust_list, 2)
2071388bb21aSths 	MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
2072388bb21aSths 	MIPS_SYS(sys_kexec_load, 4)
2073388bb21aSths 	MIPS_SYS(sys_getcpu, 3)
2074388bb21aSths 	MIPS_SYS(sys_epoll_pwait, 6)
2075388bb21aSths 	MIPS_SYS(sys_ioprio_set, 3)
2076388bb21aSths 	MIPS_SYS(sys_ioprio_get, 2)
2077d979e8ebSPeter Maydell         MIPS_SYS(sys_utimensat, 4)
2078d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd, 3)
2079d979e8ebSPeter Maydell         MIPS_SYS(sys_ni_syscall, 0)     /* was timerfd */
2080d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd, 1)
2081d979e8ebSPeter Maydell         MIPS_SYS(sys_fallocate, 6)      /* 4320 */
2082d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_create, 2)
2083d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_gettime, 2)
2084d979e8ebSPeter Maydell         MIPS_SYS(sys_timerfd_settime, 4)
2085d979e8ebSPeter Maydell         MIPS_SYS(sys_signalfd4, 4)
2086d979e8ebSPeter Maydell         MIPS_SYS(sys_eventfd2, 2)       /* 4325 */
2087d979e8ebSPeter Maydell         MIPS_SYS(sys_epoll_create1, 1)
2088d979e8ebSPeter Maydell         MIPS_SYS(sys_dup3, 3)
2089d979e8ebSPeter Maydell         MIPS_SYS(sys_pipe2, 2)
2090d979e8ebSPeter Maydell         MIPS_SYS(sys_inotify_init1, 1)
2091d979e8ebSPeter Maydell         MIPS_SYS(sys_preadv, 6)         /* 4330 */
2092d979e8ebSPeter Maydell         MIPS_SYS(sys_pwritev, 6)
2093d979e8ebSPeter Maydell         MIPS_SYS(sys_rt_tgsigqueueinfo, 4)
2094d979e8ebSPeter Maydell         MIPS_SYS(sys_perf_event_open, 5)
2095d979e8ebSPeter Maydell         MIPS_SYS(sys_accept4, 4)
2096d979e8ebSPeter Maydell         MIPS_SYS(sys_recvmmsg, 5)       /* 4335 */
2097d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_init, 2)
2098d979e8ebSPeter Maydell         MIPS_SYS(sys_fanotify_mark, 6)
2099d979e8ebSPeter Maydell         MIPS_SYS(sys_prlimit64, 4)
2100d979e8ebSPeter Maydell         MIPS_SYS(sys_name_to_handle_at, 5)
2101d979e8ebSPeter Maydell         MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */
2102d979e8ebSPeter Maydell         MIPS_SYS(sys_clock_adjtime, 2)
2103d979e8ebSPeter Maydell         MIPS_SYS(sys_syncfs, 1)
2104048f6b4dSbellard };
2105048f6b4dSbellard 
2106048f6b4dSbellard #undef MIPS_SYS
2107048f6b4dSbellard 
2108590bc601SPaul Brook static int do_store_exclusive(CPUMIPSState *env)
2109590bc601SPaul Brook {
2110590bc601SPaul Brook     target_ulong addr;
2111590bc601SPaul Brook     target_ulong page_addr;
2112590bc601SPaul Brook     target_ulong val;
2113590bc601SPaul Brook     int flags;
2114590bc601SPaul Brook     int segv = 0;
2115590bc601SPaul Brook     int reg;
2116590bc601SPaul Brook     int d;
2117590bc601SPaul Brook 
21185499b6ffSAurelien Jarno     addr = env->lladdr;
2119590bc601SPaul Brook     page_addr = addr & TARGET_PAGE_MASK;
2120590bc601SPaul Brook     start_exclusive();
2121590bc601SPaul Brook     mmap_lock();
2122590bc601SPaul Brook     flags = page_get_flags(page_addr);
2123590bc601SPaul Brook     if ((flags & PAGE_READ) == 0) {
2124590bc601SPaul Brook         segv = 1;
2125590bc601SPaul Brook     } else {
2126590bc601SPaul Brook         reg = env->llreg & 0x1f;
2127590bc601SPaul Brook         d = (env->llreg & 0x20) != 0;
2128590bc601SPaul Brook         if (d) {
2129590bc601SPaul Brook             segv = get_user_s64(val, addr);
2130590bc601SPaul Brook         } else {
2131590bc601SPaul Brook             segv = get_user_s32(val, addr);
2132590bc601SPaul Brook         }
2133590bc601SPaul Brook         if (!segv) {
2134590bc601SPaul Brook             if (val != env->llval) {
2135590bc601SPaul Brook                 env->active_tc.gpr[reg] = 0;
2136590bc601SPaul Brook             } else {
2137590bc601SPaul Brook                 if (d) {
2138590bc601SPaul Brook                     segv = put_user_u64(env->llnewval, addr);
2139590bc601SPaul Brook                 } else {
2140590bc601SPaul Brook                     segv = put_user_u32(env->llnewval, addr);
2141590bc601SPaul Brook                 }
2142590bc601SPaul Brook                 if (!segv) {
2143590bc601SPaul Brook                     env->active_tc.gpr[reg] = 1;
2144590bc601SPaul Brook                 }
2145590bc601SPaul Brook             }
2146590bc601SPaul Brook         }
2147590bc601SPaul Brook     }
21485499b6ffSAurelien Jarno     env->lladdr = -1;
2149590bc601SPaul Brook     if (!segv) {
2150590bc601SPaul Brook         env->active_tc.PC += 4;
2151590bc601SPaul Brook     }
2152590bc601SPaul Brook     mmap_unlock();
2153590bc601SPaul Brook     end_exclusive();
2154590bc601SPaul Brook     return segv;
2155590bc601SPaul Brook }
2156590bc601SPaul Brook 
2157048f6b4dSbellard void cpu_loop(CPUMIPSState *env)
2158048f6b4dSbellard {
2159c227f099SAnthony Liguori     target_siginfo_t info;
2160388bb21aSths     int trapnr, ret;
2161048f6b4dSbellard     unsigned int syscall_num;
2162048f6b4dSbellard 
2163048f6b4dSbellard     for(;;) {
2164590bc601SPaul Brook         cpu_exec_start(env);
2165048f6b4dSbellard         trapnr = cpu_mips_exec(env);
2166590bc601SPaul Brook         cpu_exec_end(env);
2167048f6b4dSbellard         switch(trapnr) {
2168048f6b4dSbellard         case EXCP_SYSCALL:
2169b5dc7732Sths             syscall_num = env->active_tc.gpr[2] - 4000;
2170b5dc7732Sths             env->active_tc.PC += 4;
2171048f6b4dSbellard             if (syscall_num >= sizeof(mips_syscall_args)) {
21727c2f6157SWesley W. Terpstra                 ret = -TARGET_ENOSYS;
2173048f6b4dSbellard             } else {
2174388bb21aSths                 int nb_args;
2175992f48a0Sblueswir1                 abi_ulong sp_reg;
2176992f48a0Sblueswir1                 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
2177388bb21aSths 
2178048f6b4dSbellard                 nb_args = mips_syscall_args[syscall_num];
2179b5dc7732Sths                 sp_reg = env->active_tc.gpr[29];
2180388bb21aSths                 switch (nb_args) {
2181048f6b4dSbellard                 /* these arguments are taken from the stack */
218294c19610SAn-Cheng Huang                 case 8:
218394c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
218494c19610SAn-Cheng Huang                         goto done_syscall;
218594c19610SAn-Cheng Huang                     }
218694c19610SAn-Cheng Huang                 case 7:
218794c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
218894c19610SAn-Cheng Huang                         goto done_syscall;
218994c19610SAn-Cheng Huang                     }
219094c19610SAn-Cheng Huang                 case 6:
219194c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
219294c19610SAn-Cheng Huang                         goto done_syscall;
219394c19610SAn-Cheng Huang                     }
219494c19610SAn-Cheng Huang                 case 5:
219594c19610SAn-Cheng Huang                     if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
219694c19610SAn-Cheng Huang                         goto done_syscall;
219794c19610SAn-Cheng Huang                     }
2198388bb21aSths                 default:
2199388bb21aSths                     break;
2200048f6b4dSbellard                 }
2201b5dc7732Sths                 ret = do_syscall(env, env->active_tc.gpr[2],
2202b5dc7732Sths                                  env->active_tc.gpr[4],
2203b5dc7732Sths                                  env->active_tc.gpr[5],
2204b5dc7732Sths                                  env->active_tc.gpr[6],
2205b5dc7732Sths                                  env->active_tc.gpr[7],
22065945cfcbSPeter Maydell                                  arg5, arg6, arg7, arg8);
2207048f6b4dSbellard             }
220894c19610SAn-Cheng Huang done_syscall:
22090b1bcb00Spbrook             if (ret == -TARGET_QEMU_ESIGRETURN) {
22100b1bcb00Spbrook                 /* Returning from a successful sigreturn syscall.
22110b1bcb00Spbrook                    Avoid clobbering register state.  */
22120b1bcb00Spbrook                 break;
22130b1bcb00Spbrook             }
2214048f6b4dSbellard             if ((unsigned int)ret >= (unsigned int)(-1133)) {
2215b5dc7732Sths                 env->active_tc.gpr[7] = 1; /* error flag */
2216048f6b4dSbellard                 ret = -ret;
2217048f6b4dSbellard             } else {
2218b5dc7732Sths                 env->active_tc.gpr[7] = 0; /* error flag */
2219388bb21aSths             }
2220b5dc7732Sths             env->active_tc.gpr[2] = ret;
2221048f6b4dSbellard             break;
2222ca7c2b1bSths         case EXCP_TLBL:
2223ca7c2b1bSths         case EXCP_TLBS:
2224e6e5bd2dSWesley W. Terpstra         case EXCP_AdEL:
2225e6e5bd2dSWesley W. Terpstra         case EXCP_AdES:
2226e4474235Spbrook             info.si_signo = TARGET_SIGSEGV;
2227e4474235Spbrook             info.si_errno = 0;
2228e4474235Spbrook             /* XXX: check env->error_code */
2229e4474235Spbrook             info.si_code = TARGET_SEGV_MAPERR;
2230e4474235Spbrook             info._sifields._sigfault._addr = env->CP0_BadVAddr;
2231e4474235Spbrook             queue_signal(env, info.si_signo, &info);
2232e4474235Spbrook             break;
22336900e84bSbellard         case EXCP_CpU:
2234048f6b4dSbellard         case EXCP_RI:
2235048f6b4dSbellard             info.si_signo = TARGET_SIGILL;
2236048f6b4dSbellard             info.si_errno = 0;
2237048f6b4dSbellard             info.si_code = 0;
2238624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2239048f6b4dSbellard             break;
2240106ec879Sbellard         case EXCP_INTERRUPT:
2241106ec879Sbellard             /* just indicate that signals should be handled asap */
2242106ec879Sbellard             break;
2243d08b2a28Spbrook         case EXCP_DEBUG:
2244d08b2a28Spbrook             {
2245d08b2a28Spbrook                 int sig;
2246d08b2a28Spbrook 
2247d08b2a28Spbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2248d08b2a28Spbrook                 if (sig)
2249d08b2a28Spbrook                   {
2250d08b2a28Spbrook                     info.si_signo = sig;
2251d08b2a28Spbrook                     info.si_errno = 0;
2252d08b2a28Spbrook                     info.si_code = TARGET_TRAP_BRKPT;
2253624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2254d08b2a28Spbrook                   }
2255d08b2a28Spbrook             }
2256d08b2a28Spbrook             break;
2257590bc601SPaul Brook         case EXCP_SC:
2258590bc601SPaul Brook             if (do_store_exclusive(env)) {
2259590bc601SPaul Brook                 info.si_signo = TARGET_SIGSEGV;
2260590bc601SPaul Brook                 info.si_errno = 0;
2261590bc601SPaul Brook                 info.si_code = TARGET_SEGV_MAPERR;
2262590bc601SPaul Brook                 info._sifields._sigfault._addr = env->active_tc.PC;
2263590bc601SPaul Brook                 queue_signal(env, info.si_signo, &info);
2264590bc601SPaul Brook             }
2265590bc601SPaul Brook             break;
2266048f6b4dSbellard         default:
2267048f6b4dSbellard             //        error:
2268048f6b4dSbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2269048f6b4dSbellard                     trapnr);
2270048f6b4dSbellard             cpu_dump_state(env, stderr, fprintf, 0);
2271048f6b4dSbellard             abort();
2272048f6b4dSbellard         }
2273048f6b4dSbellard         process_pending_signals(env);
2274048f6b4dSbellard     }
2275048f6b4dSbellard }
2276048f6b4dSbellard #endif
2277048f6b4dSbellard 
2278fdf9b3e8Sbellard #ifdef TARGET_SH4
2279fdf9b3e8Sbellard void cpu_loop (CPUState *env)
2280fdf9b3e8Sbellard {
2281fdf9b3e8Sbellard     int trapnr, ret;
2282c227f099SAnthony Liguori     target_siginfo_t info;
2283fdf9b3e8Sbellard 
2284fdf9b3e8Sbellard     while (1) {
2285fdf9b3e8Sbellard         trapnr = cpu_sh4_exec (env);
2286fdf9b3e8Sbellard 
2287fdf9b3e8Sbellard         switch (trapnr) {
2288fdf9b3e8Sbellard         case 0x160:
22890b6d3ae0Saurel32             env->pc += 2;
2290fdf9b3e8Sbellard             ret = do_syscall(env,
22919c2a9ea1Spbrook                              env->gregs[3],
22929c2a9ea1Spbrook                              env->gregs[4],
22939c2a9ea1Spbrook                              env->gregs[5],
22949c2a9ea1Spbrook                              env->gregs[6],
22959c2a9ea1Spbrook                              env->gregs[7],
22969c2a9ea1Spbrook                              env->gregs[0],
22975945cfcbSPeter Maydell                              env->gregs[1],
22985945cfcbSPeter Maydell                              0, 0);
22999c2a9ea1Spbrook             env->gregs[0] = ret;
2300fdf9b3e8Sbellard             break;
2301c3b5bc8aSths         case EXCP_INTERRUPT:
2302c3b5bc8aSths             /* just indicate that signals should be handled asap */
2303c3b5bc8aSths             break;
2304355fb23dSpbrook         case EXCP_DEBUG:
2305355fb23dSpbrook             {
2306355fb23dSpbrook                 int sig;
2307355fb23dSpbrook 
2308355fb23dSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2309355fb23dSpbrook                 if (sig)
2310355fb23dSpbrook                   {
2311355fb23dSpbrook                     info.si_signo = sig;
2312355fb23dSpbrook                     info.si_errno = 0;
2313355fb23dSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2314624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2315355fb23dSpbrook                   }
2316355fb23dSpbrook             }
2317355fb23dSpbrook             break;
2318c3b5bc8aSths 	case 0xa0:
2319c3b5bc8aSths 	case 0xc0:
2320c3b5bc8aSths             info.si_signo = SIGSEGV;
2321c3b5bc8aSths             info.si_errno = 0;
2322c3b5bc8aSths             info.si_code = TARGET_SEGV_MAPERR;
2323c3b5bc8aSths             info._sifields._sigfault._addr = env->tea;
2324624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2325c3b5bc8aSths 	    break;
2326c3b5bc8aSths 
2327fdf9b3e8Sbellard         default:
2328fdf9b3e8Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
2329fdf9b3e8Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
2330fdf9b3e8Sbellard             exit (1);
2331fdf9b3e8Sbellard         }
2332fdf9b3e8Sbellard         process_pending_signals (env);
2333fdf9b3e8Sbellard     }
2334fdf9b3e8Sbellard }
2335fdf9b3e8Sbellard #endif
2336fdf9b3e8Sbellard 
233748733d19Sths #ifdef TARGET_CRIS
233848733d19Sths void cpu_loop (CPUState *env)
233948733d19Sths {
234048733d19Sths     int trapnr, ret;
2341c227f099SAnthony Liguori     target_siginfo_t info;
234248733d19Sths 
234348733d19Sths     while (1) {
234448733d19Sths         trapnr = cpu_cris_exec (env);
234548733d19Sths         switch (trapnr) {
234648733d19Sths         case 0xaa:
234748733d19Sths             {
234848733d19Sths                 info.si_signo = SIGSEGV;
234948733d19Sths                 info.si_errno = 0;
235048733d19Sths                 /* XXX: check env->error_code */
235148733d19Sths                 info.si_code = TARGET_SEGV_MAPERR;
2352e00c1e71Sedgar_igl                 info._sifields._sigfault._addr = env->pregs[PR_EDA];
2353624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
235448733d19Sths             }
235548733d19Sths             break;
2356b6d3abdaSedgar_igl 	case EXCP_INTERRUPT:
2357b6d3abdaSedgar_igl 	  /* just indicate that signals should be handled asap */
2358b6d3abdaSedgar_igl 	  break;
235948733d19Sths         case EXCP_BREAK:
236048733d19Sths             ret = do_syscall(env,
236148733d19Sths                              env->regs[9],
236248733d19Sths                              env->regs[10],
236348733d19Sths                              env->regs[11],
236448733d19Sths                              env->regs[12],
236548733d19Sths                              env->regs[13],
236648733d19Sths                              env->pregs[7],
23675945cfcbSPeter Maydell                              env->pregs[11],
23685945cfcbSPeter Maydell                              0, 0);
236948733d19Sths             env->regs[10] = ret;
237048733d19Sths             break;
237148733d19Sths         case EXCP_DEBUG:
237248733d19Sths             {
237348733d19Sths                 int sig;
237448733d19Sths 
237548733d19Sths                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
237648733d19Sths                 if (sig)
237748733d19Sths                   {
237848733d19Sths                     info.si_signo = sig;
237948733d19Sths                     info.si_errno = 0;
238048733d19Sths                     info.si_code = TARGET_TRAP_BRKPT;
2381624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
238248733d19Sths                   }
238348733d19Sths             }
238448733d19Sths             break;
238548733d19Sths         default:
238648733d19Sths             printf ("Unhandled trap: 0x%x\n", trapnr);
238748733d19Sths             cpu_dump_state(env, stderr, fprintf, 0);
238848733d19Sths             exit (1);
238948733d19Sths         }
239048733d19Sths         process_pending_signals (env);
239148733d19Sths     }
239248733d19Sths }
239348733d19Sths #endif
239448733d19Sths 
2395b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE
2396b779e29eSEdgar E. Iglesias void cpu_loop (CPUState *env)
2397b779e29eSEdgar E. Iglesias {
2398b779e29eSEdgar E. Iglesias     int trapnr, ret;
2399c227f099SAnthony Liguori     target_siginfo_t info;
2400b779e29eSEdgar E. Iglesias 
2401b779e29eSEdgar E. Iglesias     while (1) {
2402b779e29eSEdgar E. Iglesias         trapnr = cpu_mb_exec (env);
2403b779e29eSEdgar E. Iglesias         switch (trapnr) {
2404b779e29eSEdgar E. Iglesias         case 0xaa:
2405b779e29eSEdgar E. Iglesias             {
2406b779e29eSEdgar E. Iglesias                 info.si_signo = SIGSEGV;
2407b779e29eSEdgar E. Iglesias                 info.si_errno = 0;
2408b779e29eSEdgar E. Iglesias                 /* XXX: check env->error_code */
2409b779e29eSEdgar E. Iglesias                 info.si_code = TARGET_SEGV_MAPERR;
2410b779e29eSEdgar E. Iglesias                 info._sifields._sigfault._addr = 0;
2411b779e29eSEdgar E. Iglesias                 queue_signal(env, info.si_signo, &info);
2412b779e29eSEdgar E. Iglesias             }
2413b779e29eSEdgar E. Iglesias             break;
2414b779e29eSEdgar E. Iglesias 	case EXCP_INTERRUPT:
2415b779e29eSEdgar E. Iglesias 	  /* just indicate that signals should be handled asap */
2416b779e29eSEdgar E. Iglesias 	  break;
2417b779e29eSEdgar E. Iglesias         case EXCP_BREAK:
2418b779e29eSEdgar E. Iglesias             /* Return address is 4 bytes after the call.  */
2419b779e29eSEdgar E. Iglesias             env->regs[14] += 4;
2420b779e29eSEdgar E. Iglesias             ret = do_syscall(env,
2421b779e29eSEdgar E. Iglesias                              env->regs[12],
2422b779e29eSEdgar E. Iglesias                              env->regs[5],
2423b779e29eSEdgar E. Iglesias                              env->regs[6],
2424b779e29eSEdgar E. Iglesias                              env->regs[7],
2425b779e29eSEdgar E. Iglesias                              env->regs[8],
2426b779e29eSEdgar E. Iglesias                              env->regs[9],
24275945cfcbSPeter Maydell                              env->regs[10],
24285945cfcbSPeter Maydell                              0, 0);
2429b779e29eSEdgar E. Iglesias             env->regs[3] = ret;
2430b779e29eSEdgar E. Iglesias             env->sregs[SR_PC] = env->regs[14];
2431b779e29eSEdgar E. Iglesias             break;
2432b76da7e3SEdgar E. Iglesias         case EXCP_HW_EXCP:
2433b76da7e3SEdgar E. Iglesias             env->regs[17] = env->sregs[SR_PC] + 4;
2434b76da7e3SEdgar E. Iglesias             if (env->iflags & D_FLAG) {
2435b76da7e3SEdgar E. Iglesias                 env->sregs[SR_ESR] |= 1 << 12;
2436b76da7e3SEdgar E. Iglesias                 env->sregs[SR_PC] -= 4;
2437b76da7e3SEdgar E. Iglesias                 /* FIXME: if branch was immed, replay the imm as well.  */
2438b76da7e3SEdgar E. Iglesias             }
2439b76da7e3SEdgar E. Iglesias 
2440b76da7e3SEdgar E. Iglesias             env->iflags &= ~(IMM_FLAG | D_FLAG);
2441b76da7e3SEdgar E. Iglesias 
2442b76da7e3SEdgar E. Iglesias             switch (env->sregs[SR_ESR] & 31) {
244322a78d64SEdgar E. Iglesias                 case ESR_EC_DIVZERO:
244422a78d64SEdgar E. Iglesias                     info.si_signo = SIGFPE;
244522a78d64SEdgar E. Iglesias                     info.si_errno = 0;
244622a78d64SEdgar E. Iglesias                     info.si_code = TARGET_FPE_FLTDIV;
244722a78d64SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
244822a78d64SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
244922a78d64SEdgar E. Iglesias                     break;
2450b76da7e3SEdgar E. Iglesias                 case ESR_EC_FPU:
2451b76da7e3SEdgar E. Iglesias                     info.si_signo = SIGFPE;
2452b76da7e3SEdgar E. Iglesias                     info.si_errno = 0;
2453b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_IO) {
2454b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTINV;
2455b76da7e3SEdgar E. Iglesias                     }
2456b76da7e3SEdgar E. Iglesias                     if (env->sregs[SR_FSR] & FSR_DZ) {
2457b76da7e3SEdgar E. Iglesias                         info.si_code = TARGET_FPE_FLTDIV;
2458b76da7e3SEdgar E. Iglesias                     }
2459b76da7e3SEdgar E. Iglesias                     info._sifields._sigfault._addr = 0;
2460b76da7e3SEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2461b76da7e3SEdgar E. Iglesias                     break;
2462b76da7e3SEdgar E. Iglesias                 default:
2463b76da7e3SEdgar E. Iglesias                     printf ("Unhandled hw-exception: 0x%x\n",
24642e42d52dSEdgar E. Iglesias                             env->sregs[SR_ESR] & ESR_EC_MASK);
2465b76da7e3SEdgar E. Iglesias                     cpu_dump_state(env, stderr, fprintf, 0);
2466b76da7e3SEdgar E. Iglesias                     exit (1);
2467b76da7e3SEdgar E. Iglesias                     break;
2468b76da7e3SEdgar E. Iglesias             }
2469b76da7e3SEdgar E. Iglesias             break;
2470b779e29eSEdgar E. Iglesias         case EXCP_DEBUG:
2471b779e29eSEdgar E. Iglesias             {
2472b779e29eSEdgar E. Iglesias                 int sig;
2473b779e29eSEdgar E. Iglesias 
2474b779e29eSEdgar E. Iglesias                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2475b779e29eSEdgar E. Iglesias                 if (sig)
2476b779e29eSEdgar E. Iglesias                   {
2477b779e29eSEdgar E. Iglesias                     info.si_signo = sig;
2478b779e29eSEdgar E. Iglesias                     info.si_errno = 0;
2479b779e29eSEdgar E. Iglesias                     info.si_code = TARGET_TRAP_BRKPT;
2480b779e29eSEdgar E. Iglesias                     queue_signal(env, info.si_signo, &info);
2481b779e29eSEdgar E. Iglesias                   }
2482b779e29eSEdgar E. Iglesias             }
2483b779e29eSEdgar E. Iglesias             break;
2484b779e29eSEdgar E. Iglesias         default:
2485b779e29eSEdgar E. Iglesias             printf ("Unhandled trap: 0x%x\n", trapnr);
2486b779e29eSEdgar E. Iglesias             cpu_dump_state(env, stderr, fprintf, 0);
2487b779e29eSEdgar E. Iglesias             exit (1);
2488b779e29eSEdgar E. Iglesias         }
2489b779e29eSEdgar E. Iglesias         process_pending_signals (env);
2490b779e29eSEdgar E. Iglesias     }
2491b779e29eSEdgar E. Iglesias }
2492b779e29eSEdgar E. Iglesias #endif
2493b779e29eSEdgar E. Iglesias 
2494e6e5906bSpbrook #ifdef TARGET_M68K
2495e6e5906bSpbrook 
2496e6e5906bSpbrook void cpu_loop(CPUM68KState *env)
2497e6e5906bSpbrook {
2498e6e5906bSpbrook     int trapnr;
2499e6e5906bSpbrook     unsigned int n;
2500c227f099SAnthony Liguori     target_siginfo_t info;
2501e6e5906bSpbrook     TaskState *ts = env->opaque;
2502e6e5906bSpbrook 
2503e6e5906bSpbrook     for(;;) {
2504e6e5906bSpbrook         trapnr = cpu_m68k_exec(env);
2505e6e5906bSpbrook         switch(trapnr) {
2506e6e5906bSpbrook         case EXCP_ILLEGAL:
2507e6e5906bSpbrook             {
2508e6e5906bSpbrook                 if (ts->sim_syscalls) {
2509e6e5906bSpbrook                     uint16_t nr;
2510e6e5906bSpbrook                     nr = lduw(env->pc + 2);
2511e6e5906bSpbrook                     env->pc += 4;
2512e6e5906bSpbrook                     do_m68k_simcall(env, nr);
2513e6e5906bSpbrook                 } else {
2514e6e5906bSpbrook                     goto do_sigill;
2515e6e5906bSpbrook                 }
2516e6e5906bSpbrook             }
2517e6e5906bSpbrook             break;
2518a87295e8Spbrook         case EXCP_HALT_INSN:
2519e6e5906bSpbrook             /* Semihosing syscall.  */
2520a87295e8Spbrook             env->pc += 4;
2521e6e5906bSpbrook             do_m68k_semihosting(env, env->dregs[0]);
2522e6e5906bSpbrook             break;
2523e6e5906bSpbrook         case EXCP_LINEA:
2524e6e5906bSpbrook         case EXCP_LINEF:
2525e6e5906bSpbrook         case EXCP_UNSUPPORTED:
2526e6e5906bSpbrook         do_sigill:
2527e6e5906bSpbrook             info.si_signo = SIGILL;
2528e6e5906bSpbrook             info.si_errno = 0;
2529e6e5906bSpbrook             info.si_code = TARGET_ILL_ILLOPN;
2530e6e5906bSpbrook             info._sifields._sigfault._addr = env->pc;
2531624f7979Spbrook             queue_signal(env, info.si_signo, &info);
2532e6e5906bSpbrook             break;
2533e6e5906bSpbrook         case EXCP_TRAP0:
2534e6e5906bSpbrook             {
2535e6e5906bSpbrook                 ts->sim_syscalls = 0;
2536e6e5906bSpbrook                 n = env->dregs[0];
2537e6e5906bSpbrook                 env->pc += 2;
2538e6e5906bSpbrook                 env->dregs[0] = do_syscall(env,
2539e6e5906bSpbrook                                           n,
2540e6e5906bSpbrook                                           env->dregs[1],
2541e6e5906bSpbrook                                           env->dregs[2],
2542e6e5906bSpbrook                                           env->dregs[3],
2543e6e5906bSpbrook                                           env->dregs[4],
2544e6e5906bSpbrook                                           env->dregs[5],
25455945cfcbSPeter Maydell                                           env->aregs[0],
25465945cfcbSPeter Maydell                                           0, 0);
2547e6e5906bSpbrook             }
2548e6e5906bSpbrook             break;
2549e6e5906bSpbrook         case EXCP_INTERRUPT:
2550e6e5906bSpbrook             /* just indicate that signals should be handled asap */
2551e6e5906bSpbrook             break;
2552e6e5906bSpbrook         case EXCP_ACCESS:
2553e6e5906bSpbrook             {
2554e6e5906bSpbrook                 info.si_signo = SIGSEGV;
2555e6e5906bSpbrook                 info.si_errno = 0;
2556e6e5906bSpbrook                 /* XXX: check env->error_code */
2557e6e5906bSpbrook                 info.si_code = TARGET_SEGV_MAPERR;
2558e6e5906bSpbrook                 info._sifields._sigfault._addr = env->mmu.ar;
2559624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
2560e6e5906bSpbrook             }
2561e6e5906bSpbrook             break;
2562e6e5906bSpbrook         case EXCP_DEBUG:
2563e6e5906bSpbrook             {
2564e6e5906bSpbrook                 int sig;
2565e6e5906bSpbrook 
2566e6e5906bSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2567e6e5906bSpbrook                 if (sig)
2568e6e5906bSpbrook                   {
2569e6e5906bSpbrook                     info.si_signo = sig;
2570e6e5906bSpbrook                     info.si_errno = 0;
2571e6e5906bSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
2572624f7979Spbrook                     queue_signal(env, info.si_signo, &info);
2573e6e5906bSpbrook                   }
2574e6e5906bSpbrook             }
2575e6e5906bSpbrook             break;
2576e6e5906bSpbrook         default:
2577e6e5906bSpbrook             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
2578e6e5906bSpbrook                     trapnr);
2579e6e5906bSpbrook             cpu_dump_state(env, stderr, fprintf, 0);
2580e6e5906bSpbrook             abort();
2581e6e5906bSpbrook         }
2582e6e5906bSpbrook         process_pending_signals(env);
2583e6e5906bSpbrook     }
2584e6e5906bSpbrook }
2585e6e5906bSpbrook #endif /* TARGET_M68K */
2586e6e5906bSpbrook 
25877a3148a9Sj_mayer #ifdef TARGET_ALPHA
25886910b8f6SRichard Henderson static void do_store_exclusive(CPUAlphaState *env, int reg, int quad)
25896910b8f6SRichard Henderson {
25906910b8f6SRichard Henderson     target_ulong addr, val, tmp;
25916910b8f6SRichard Henderson     target_siginfo_t info;
25926910b8f6SRichard Henderson     int ret = 0;
25936910b8f6SRichard Henderson 
25946910b8f6SRichard Henderson     addr = env->lock_addr;
25956910b8f6SRichard Henderson     tmp = env->lock_st_addr;
25966910b8f6SRichard Henderson     env->lock_addr = -1;
25976910b8f6SRichard Henderson     env->lock_st_addr = 0;
25986910b8f6SRichard Henderson 
25996910b8f6SRichard Henderson     start_exclusive();
26006910b8f6SRichard Henderson     mmap_lock();
26016910b8f6SRichard Henderson 
26026910b8f6SRichard Henderson     if (addr == tmp) {
26036910b8f6SRichard Henderson         if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
26046910b8f6SRichard Henderson             goto do_sigsegv;
26056910b8f6SRichard Henderson         }
26066910b8f6SRichard Henderson 
26076910b8f6SRichard Henderson         if (val == env->lock_value) {
26086910b8f6SRichard Henderson             tmp = env->ir[reg];
26096910b8f6SRichard Henderson             if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) {
26106910b8f6SRichard Henderson                 goto do_sigsegv;
26116910b8f6SRichard Henderson             }
26126910b8f6SRichard Henderson             ret = 1;
26136910b8f6SRichard Henderson         }
26146910b8f6SRichard Henderson     }
26156910b8f6SRichard Henderson     env->ir[reg] = ret;
26166910b8f6SRichard Henderson     env->pc += 4;
26176910b8f6SRichard Henderson 
26186910b8f6SRichard Henderson     mmap_unlock();
26196910b8f6SRichard Henderson     end_exclusive();
26206910b8f6SRichard Henderson     return;
26216910b8f6SRichard Henderson 
26226910b8f6SRichard Henderson  do_sigsegv:
26236910b8f6SRichard Henderson     mmap_unlock();
26246910b8f6SRichard Henderson     end_exclusive();
26256910b8f6SRichard Henderson 
26266910b8f6SRichard Henderson     info.si_signo = TARGET_SIGSEGV;
26276910b8f6SRichard Henderson     info.si_errno = 0;
26286910b8f6SRichard Henderson     info.si_code = TARGET_SEGV_MAPERR;
26296910b8f6SRichard Henderson     info._sifields._sigfault._addr = addr;
26306910b8f6SRichard Henderson     queue_signal(env, TARGET_SIGSEGV, &info);
26316910b8f6SRichard Henderson }
26326910b8f6SRichard Henderson 
26337a3148a9Sj_mayer void cpu_loop (CPUState *env)
26347a3148a9Sj_mayer {
2635e96efcfcSj_mayer     int trapnr;
2636c227f099SAnthony Liguori     target_siginfo_t info;
26376049f4f8SRichard Henderson     abi_long sysret;
26387a3148a9Sj_mayer 
26397a3148a9Sj_mayer     while (1) {
26407a3148a9Sj_mayer         trapnr = cpu_alpha_exec (env);
26417a3148a9Sj_mayer 
2642ac316ca4SRichard Henderson         /* All of the traps imply a transition through PALcode, which
2643ac316ca4SRichard Henderson            implies an REI instruction has been executed.  Which means
2644ac316ca4SRichard Henderson            that the intr_flag should be cleared.  */
2645ac316ca4SRichard Henderson         env->intr_flag = 0;
2646ac316ca4SRichard Henderson 
26477a3148a9Sj_mayer         switch (trapnr) {
26487a3148a9Sj_mayer         case EXCP_RESET:
26497a3148a9Sj_mayer             fprintf(stderr, "Reset requested. Exit\n");
26507a3148a9Sj_mayer             exit(1);
26517a3148a9Sj_mayer             break;
26527a3148a9Sj_mayer         case EXCP_MCHK:
26537a3148a9Sj_mayer             fprintf(stderr, "Machine check exception. Exit\n");
26547a3148a9Sj_mayer             exit(1);
26557a3148a9Sj_mayer             break;
265607b6c13bSRichard Henderson         case EXCP_SMP_INTERRUPT:
265707b6c13bSRichard Henderson         case EXCP_CLK_INTERRUPT:
265807b6c13bSRichard Henderson         case EXCP_DEV_INTERRUPT:
26597a3148a9Sj_mayer             fprintf(stderr, "External interrupt. Exit\n");
26607a3148a9Sj_mayer             exit(1);
26617a3148a9Sj_mayer             break;
266207b6c13bSRichard Henderson         case EXCP_MMFAULT:
26636910b8f6SRichard Henderson             env->lock_addr = -1;
26646049f4f8SRichard Henderson             info.si_signo = TARGET_SIGSEGV;
26656049f4f8SRichard Henderson             info.si_errno = 0;
2666129d8aa5SRichard Henderson             info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
26670be1d07cSRichard Henderson                             ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
2668129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
26696049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
26707a3148a9Sj_mayer             break;
26717a3148a9Sj_mayer         case EXCP_UNALIGN:
26726910b8f6SRichard Henderson             env->lock_addr = -1;
26736049f4f8SRichard Henderson             info.si_signo = TARGET_SIGBUS;
26746049f4f8SRichard Henderson             info.si_errno = 0;
26756049f4f8SRichard Henderson             info.si_code = TARGET_BUS_ADRALN;
2676129d8aa5SRichard Henderson             info._sifields._sigfault._addr = env->trap_arg0;
26776049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
26787a3148a9Sj_mayer             break;
26797a3148a9Sj_mayer         case EXCP_OPCDEC:
26806049f4f8SRichard Henderson         do_sigill:
26816910b8f6SRichard Henderson             env->lock_addr = -1;
26826049f4f8SRichard Henderson             info.si_signo = TARGET_SIGILL;
26836049f4f8SRichard Henderson             info.si_errno = 0;
26846049f4f8SRichard Henderson             info.si_code = TARGET_ILL_ILLOPC;
26856049f4f8SRichard Henderson             info._sifields._sigfault._addr = env->pc;
26866049f4f8SRichard Henderson             queue_signal(env, info.si_signo, &info);
26877a3148a9Sj_mayer             break;
268807b6c13bSRichard Henderson         case EXCP_ARITH:
268907b6c13bSRichard Henderson             env->lock_addr = -1;
269007b6c13bSRichard Henderson             info.si_signo = TARGET_SIGFPE;
269107b6c13bSRichard Henderson             info.si_errno = 0;
269207b6c13bSRichard Henderson             info.si_code = TARGET_FPE_FLTINV;
269307b6c13bSRichard Henderson             info._sifields._sigfault._addr = env->pc;
269407b6c13bSRichard Henderson             queue_signal(env, info.si_signo, &info);
269507b6c13bSRichard Henderson             break;
26967a3148a9Sj_mayer         case EXCP_FEN:
26976049f4f8SRichard Henderson             /* No-op.  Linux simply re-enables the FPU.  */
26987a3148a9Sj_mayer             break;
269907b6c13bSRichard Henderson         case EXCP_CALL_PAL:
27006910b8f6SRichard Henderson             env->lock_addr = -1;
270107b6c13bSRichard Henderson             switch (env->error_code) {
27026049f4f8SRichard Henderson             case 0x80:
27036049f4f8SRichard Henderson                 /* BPT */
27046049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
27056049f4f8SRichard Henderson                 info.si_errno = 0;
27066049f4f8SRichard Henderson                 info.si_code = TARGET_TRAP_BRKPT;
27076049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
27086049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
27096049f4f8SRichard Henderson                 break;
27106049f4f8SRichard Henderson             case 0x81:
27116049f4f8SRichard Henderson                 /* BUGCHK */
27126049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGTRAP;
27136049f4f8SRichard Henderson                 info.si_errno = 0;
27146049f4f8SRichard Henderson                 info.si_code = 0;
27156049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
27166049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
27176049f4f8SRichard Henderson                 break;
27186049f4f8SRichard Henderson             case 0x83:
27196049f4f8SRichard Henderson                 /* CALLSYS */
27206049f4f8SRichard Henderson                 trapnr = env->ir[IR_V0];
27216049f4f8SRichard Henderson                 sysret = do_syscall(env, trapnr,
27226049f4f8SRichard Henderson                                     env->ir[IR_A0], env->ir[IR_A1],
27236049f4f8SRichard Henderson                                     env->ir[IR_A2], env->ir[IR_A3],
27245945cfcbSPeter Maydell                                     env->ir[IR_A4], env->ir[IR_A5],
27255945cfcbSPeter Maydell                                     0, 0);
2726a5b3b13bSRichard Henderson                 if (trapnr == TARGET_NR_sigreturn
2727a5b3b13bSRichard Henderson                     || trapnr == TARGET_NR_rt_sigreturn) {
2728a5b3b13bSRichard Henderson                     break;
2729a5b3b13bSRichard Henderson                 }
2730a5b3b13bSRichard Henderson                 /* Syscall writes 0 to V0 to bypass error check, similar
2731a5b3b13bSRichard Henderson                    to how this is handled internal to Linux kernel.  */
2732a5b3b13bSRichard Henderson                 if (env->ir[IR_V0] == 0) {
2733a5b3b13bSRichard Henderson                     env->ir[IR_V0] = sysret;
2734a5b3b13bSRichard Henderson                 } else {
27356049f4f8SRichard Henderson                     env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret);
27366049f4f8SRichard Henderson                     env->ir[IR_A3] = (sysret < 0);
27376049f4f8SRichard Henderson                 }
27386049f4f8SRichard Henderson                 break;
27396049f4f8SRichard Henderson             case 0x86:
27406049f4f8SRichard Henderson                 /* IMB */
27416049f4f8SRichard Henderson                 /* ??? We can probably elide the code using page_unprotect
27426049f4f8SRichard Henderson                    that is checking for self-modifying code.  Instead we
27436049f4f8SRichard Henderson                    could simply call tb_flush here.  Until we work out the
27446049f4f8SRichard Henderson                    changes required to turn off the extra write protection,
27456049f4f8SRichard Henderson                    this can be a no-op.  */
27466049f4f8SRichard Henderson                 break;
27476049f4f8SRichard Henderson             case 0x9E:
27486049f4f8SRichard Henderson                 /* RDUNIQUE */
27496049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
27506049f4f8SRichard Henderson                 abort();
27516049f4f8SRichard Henderson             case 0x9F:
27526049f4f8SRichard Henderson                 /* WRUNIQUE */
27536049f4f8SRichard Henderson                 /* Handled in the translator for usermode.  */
27546049f4f8SRichard Henderson                 abort();
27556049f4f8SRichard Henderson             case 0xAA:
27566049f4f8SRichard Henderson                 /* GENTRAP */
27576049f4f8SRichard Henderson                 info.si_signo = TARGET_SIGFPE;
27586049f4f8SRichard Henderson                 switch (env->ir[IR_A0]) {
27596049f4f8SRichard Henderson                 case TARGET_GEN_INTOVF:
27606049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTOVF;
27616049f4f8SRichard Henderson                     break;
27626049f4f8SRichard Henderson                 case TARGET_GEN_INTDIV:
27636049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_INTDIV;
27646049f4f8SRichard Henderson                     break;
27656049f4f8SRichard Henderson                 case TARGET_GEN_FLTOVF:
27666049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTOVF;
27676049f4f8SRichard Henderson                     break;
27686049f4f8SRichard Henderson                 case TARGET_GEN_FLTUND:
27696049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTUND;
27706049f4f8SRichard Henderson                     break;
27716049f4f8SRichard Henderson                 case TARGET_GEN_FLTINV:
27726049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTINV;
27736049f4f8SRichard Henderson                     break;
27746049f4f8SRichard Henderson                 case TARGET_GEN_FLTINE:
27756049f4f8SRichard Henderson                     info.si_code = TARGET_FPE_FLTRES;
27766049f4f8SRichard Henderson                     break;
27776049f4f8SRichard Henderson                 case TARGET_GEN_ROPRAND:
27786049f4f8SRichard Henderson                     info.si_code = 0;
27796049f4f8SRichard Henderson                     break;
27806049f4f8SRichard Henderson                 default:
27816049f4f8SRichard Henderson                     info.si_signo = TARGET_SIGTRAP;
27826049f4f8SRichard Henderson                     info.si_code = 0;
27836049f4f8SRichard Henderson                     break;
27846049f4f8SRichard Henderson                 }
27856049f4f8SRichard Henderson                 info.si_errno = 0;
27866049f4f8SRichard Henderson                 info._sifields._sigfault._addr = env->pc;
27876049f4f8SRichard Henderson                 queue_signal(env, info.si_signo, &info);
27886049f4f8SRichard Henderson                 break;
27896049f4f8SRichard Henderson             default:
27906049f4f8SRichard Henderson                 goto do_sigill;
27916049f4f8SRichard Henderson             }
27927a3148a9Sj_mayer             break;
27937a3148a9Sj_mayer         case EXCP_DEBUG:
27946049f4f8SRichard Henderson             info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
27956049f4f8SRichard Henderson             if (info.si_signo) {
27966910b8f6SRichard Henderson                 env->lock_addr = -1;
27977a3148a9Sj_mayer                 info.si_errno = 0;
27987a3148a9Sj_mayer                 info.si_code = TARGET_TRAP_BRKPT;
2799624f7979Spbrook                 queue_signal(env, info.si_signo, &info);
28007a3148a9Sj_mayer             }
28017a3148a9Sj_mayer             break;
28026910b8f6SRichard Henderson         case EXCP_STL_C:
28036910b8f6SRichard Henderson         case EXCP_STQ_C:
28046910b8f6SRichard Henderson             do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
28056910b8f6SRichard Henderson             break;
28067a3148a9Sj_mayer         default:
28077a3148a9Sj_mayer             printf ("Unhandled trap: 0x%x\n", trapnr);
28087a3148a9Sj_mayer             cpu_dump_state(env, stderr, fprintf, 0);
28097a3148a9Sj_mayer             exit (1);
28107a3148a9Sj_mayer         }
28117a3148a9Sj_mayer         process_pending_signals (env);
28127a3148a9Sj_mayer     }
28137a3148a9Sj_mayer }
28147a3148a9Sj_mayer #endif /* TARGET_ALPHA */
28157a3148a9Sj_mayer 
2816a4c075f1SUlrich Hecht #ifdef TARGET_S390X
2817a4c075f1SUlrich Hecht void cpu_loop(CPUS390XState *env)
2818a4c075f1SUlrich Hecht {
2819a4c075f1SUlrich Hecht     int trapnr;
2820a4c075f1SUlrich Hecht     target_siginfo_t info;
2821a4c075f1SUlrich Hecht 
2822a4c075f1SUlrich Hecht     while (1) {
2823a4c075f1SUlrich Hecht         trapnr = cpu_s390x_exec (env);
2824a4c075f1SUlrich Hecht 
2825a4c075f1SUlrich Hecht         switch (trapnr) {
2826a4c075f1SUlrich Hecht         case EXCP_INTERRUPT:
2827a4c075f1SUlrich Hecht             /* just indicate that signals should be handled asap */
2828a4c075f1SUlrich Hecht             break;
2829a4c075f1SUlrich Hecht         case EXCP_DEBUG:
2830a4c075f1SUlrich Hecht             {
2831a4c075f1SUlrich Hecht                 int sig;
2832a4c075f1SUlrich Hecht 
2833a4c075f1SUlrich Hecht                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2834a4c075f1SUlrich Hecht                 if (sig) {
2835a4c075f1SUlrich Hecht                     info.si_signo = sig;
2836a4c075f1SUlrich Hecht                     info.si_errno = 0;
2837a4c075f1SUlrich Hecht                     info.si_code = TARGET_TRAP_BRKPT;
2838a4c075f1SUlrich Hecht                     queue_signal(env, info.si_signo, &info);
2839a4c075f1SUlrich Hecht                 }
2840a4c075f1SUlrich Hecht             }
2841a4c075f1SUlrich Hecht             break;
2842a4c075f1SUlrich Hecht         case EXCP_SVC:
2843a4c075f1SUlrich Hecht             {
2844a4c075f1SUlrich Hecht                 int n = env->int_svc_code;
2845a4c075f1SUlrich Hecht                 if (!n) {
2846a4c075f1SUlrich Hecht                     /* syscalls > 255 */
2847a4c075f1SUlrich Hecht                     n = env->regs[1];
2848a4c075f1SUlrich Hecht                 }
2849a4c075f1SUlrich Hecht                 env->psw.addr += env->int_svc_ilc;
2850a4c075f1SUlrich Hecht                 env->regs[2] = do_syscall(env, n,
2851a4c075f1SUlrich Hecht                            env->regs[2],
2852a4c075f1SUlrich Hecht                            env->regs[3],
2853a4c075f1SUlrich Hecht                            env->regs[4],
2854a4c075f1SUlrich Hecht                            env->regs[5],
2855a4c075f1SUlrich Hecht                            env->regs[6],
28565945cfcbSPeter Maydell                            env->regs[7],
28575945cfcbSPeter Maydell                            0, 0);
2858a4c075f1SUlrich Hecht             }
2859a4c075f1SUlrich Hecht             break;
2860a4c075f1SUlrich Hecht         case EXCP_ADDR:
2861a4c075f1SUlrich Hecht             {
2862a4c075f1SUlrich Hecht                 info.si_signo = SIGSEGV;
2863a4c075f1SUlrich Hecht                 info.si_errno = 0;
2864a4c075f1SUlrich Hecht                 /* XXX: check env->error_code */
2865a4c075f1SUlrich Hecht                 info.si_code = TARGET_SEGV_MAPERR;
2866a4c075f1SUlrich Hecht                 info._sifields._sigfault._addr = env->__excp_addr;
2867a4c075f1SUlrich Hecht                 queue_signal(env, info.si_signo, &info);
2868a4c075f1SUlrich Hecht             }
2869a4c075f1SUlrich Hecht             break;
2870a4c075f1SUlrich Hecht         case EXCP_SPEC:
2871a4c075f1SUlrich Hecht             {
2872a4c075f1SUlrich Hecht                 fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4));
2873a4c075f1SUlrich Hecht                 info.si_signo = SIGILL;
2874a4c075f1SUlrich Hecht                 info.si_errno = 0;
2875a4c075f1SUlrich Hecht                 info.si_code = TARGET_ILL_ILLOPC;
2876a4c075f1SUlrich Hecht                 info._sifields._sigfault._addr = env->__excp_addr;
2877a4c075f1SUlrich Hecht                 queue_signal(env, info.si_signo, &info);
2878a4c075f1SUlrich Hecht             }
2879a4c075f1SUlrich Hecht             break;
2880a4c075f1SUlrich Hecht         default:
2881a4c075f1SUlrich Hecht             printf ("Unhandled trap: 0x%x\n", trapnr);
2882a4c075f1SUlrich Hecht             cpu_dump_state(env, stderr, fprintf, 0);
2883a4c075f1SUlrich Hecht             exit (1);
2884a4c075f1SUlrich Hecht         }
2885a4c075f1SUlrich Hecht         process_pending_signals (env);
2886a4c075f1SUlrich Hecht     }
2887a4c075f1SUlrich Hecht }
2888a4c075f1SUlrich Hecht 
2889a4c075f1SUlrich Hecht #endif /* TARGET_S390X */
2890a4c075f1SUlrich Hecht 
2891d5975363Spbrook THREAD CPUState *thread_env;
289259faf6d6Sbellard 
2893edf8e2afSMika Westerberg void task_settid(TaskState *ts)
2894edf8e2afSMika Westerberg {
2895edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
28962f7bb878SJuan Quintela #ifdef CONFIG_USE_NPTL
2897edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
2898edf8e2afSMika Westerberg #else
2899edf8e2afSMika Westerberg         /* when no threads are used, tid becomes pid */
2900edf8e2afSMika Westerberg         ts->ts_tid = getpid();
2901edf8e2afSMika Westerberg #endif
2902edf8e2afSMika Westerberg     }
2903edf8e2afSMika Westerberg }
2904edf8e2afSMika Westerberg 
2905edf8e2afSMika Westerberg void stop_all_tasks(void)
2906edf8e2afSMika Westerberg {
2907edf8e2afSMika Westerberg     /*
2908edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
2909edf8e2afSMika Westerberg      * handles thread stopping correctly.
2910edf8e2afSMika Westerberg      */
2911edf8e2afSMika Westerberg     start_exclusive();
2912edf8e2afSMika Westerberg }
2913edf8e2afSMika Westerberg 
2914c3a92833Spbrook /* Assumes contents are already zeroed.  */
2915624f7979Spbrook void init_task_state(TaskState *ts)
2916624f7979Spbrook {
2917624f7979Spbrook     int i;
2918624f7979Spbrook 
2919624f7979Spbrook     ts->used = 1;
2920624f7979Spbrook     ts->first_free = ts->sigqueue_table;
2921624f7979Spbrook     for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
2922624f7979Spbrook         ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
2923624f7979Spbrook     }
2924624f7979Spbrook     ts->sigqueue_table[i].next = NULL;
2925624f7979Spbrook }
29269de5e440Sbellard 
2927fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
2928fc9c5412SJohannes Schauer {
2929fc9c5412SJohannes Schauer     usage();
2930fc9c5412SJohannes Schauer }
2931fc9c5412SJohannes Schauer 
2932fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
2933fc9c5412SJohannes Schauer {
2934fc9c5412SJohannes Schauer     int mask;
2935fc9c5412SJohannes Schauer     const CPULogItem *item;
2936fc9c5412SJohannes Schauer 
2937fc9c5412SJohannes Schauer     mask = cpu_str_to_log_mask(arg);
2938fc9c5412SJohannes Schauer     if (!mask) {
2939fc9c5412SJohannes Schauer         printf("Log items (comma separated):\n");
2940fc9c5412SJohannes Schauer         for (item = cpu_log_items; item->mask != 0; item++) {
2941fc9c5412SJohannes Schauer             printf("%-10s %s\n", item->name, item->help);
2942fc9c5412SJohannes Schauer         }
2943fc9c5412SJohannes Schauer         exit(1);
2944fc9c5412SJohannes Schauer     }
2945fc9c5412SJohannes Schauer     cpu_set_log(mask);
2946fc9c5412SJohannes Schauer }
2947fc9c5412SJohannes Schauer 
2948fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
2949fc9c5412SJohannes Schauer {
2950fc9c5412SJohannes Schauer     char *r, *p, *token;
2951fc9c5412SJohannes Schauer     r = p = strdup(arg);
2952fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
2953fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
2954fc9c5412SJohannes Schauer             usage();
2955fc9c5412SJohannes Schauer         }
2956fc9c5412SJohannes Schauer     }
2957fc9c5412SJohannes Schauer     free(r);
2958fc9c5412SJohannes Schauer }
2959fc9c5412SJohannes Schauer 
2960fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
2961fc9c5412SJohannes Schauer {
2962fc9c5412SJohannes Schauer     char *r, *p, *token;
2963fc9c5412SJohannes Schauer     r = p = strdup(arg);
2964fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
2965fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
2966fc9c5412SJohannes Schauer             usage();
2967fc9c5412SJohannes Schauer         }
2968fc9c5412SJohannes Schauer     }
2969fc9c5412SJohannes Schauer     free(r);
2970fc9c5412SJohannes Schauer }
2971fc9c5412SJohannes Schauer 
2972fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
2973fc9c5412SJohannes Schauer {
2974fc9c5412SJohannes Schauer     argv0 = strdup(arg);
2975fc9c5412SJohannes Schauer }
2976fc9c5412SJohannes Schauer 
2977fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
2978fc9c5412SJohannes Schauer {
2979fc9c5412SJohannes Schauer     char *p;
2980fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
2981fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
2982fc9c5412SJohannes Schauer         usage();
2983fc9c5412SJohannes Schauer     }
2984fc9c5412SJohannes Schauer 
2985fc9c5412SJohannes Schauer     if (*p == 'M') {
2986fc9c5412SJohannes Schauer         guest_stack_size *= 1024 * 1024;
2987fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
2988fc9c5412SJohannes Schauer         guest_stack_size *= 1024;
2989fc9c5412SJohannes Schauer     }
2990fc9c5412SJohannes Schauer }
2991fc9c5412SJohannes Schauer 
2992fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
2993fc9c5412SJohannes Schauer {
2994fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
2995fc9c5412SJohannes Schauer }
2996fc9c5412SJohannes Schauer 
2997fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
2998fc9c5412SJohannes Schauer {
2999fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
3000fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
3001fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
3002fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
3003fc9c5412SJohannes Schauer         exit(1);
3004fc9c5412SJohannes Schauer     }
3005fc9c5412SJohannes Schauer }
3006fc9c5412SJohannes Schauer 
3007fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
3008fc9c5412SJohannes Schauer {
3009fc9c5412SJohannes Schauer     gdbstub_port = atoi(arg);
3010fc9c5412SJohannes Schauer }
3011fc9c5412SJohannes Schauer 
3012fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
3013fc9c5412SJohannes Schauer {
3014fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
3015fc9c5412SJohannes Schauer }
3016fc9c5412SJohannes Schauer 
3017fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
3018fc9c5412SJohannes Schauer {
3019fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
3020fc9c5412SJohannes Schauer     if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
3021fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
3022fc9c5412SJohannes Schauer #if defined(cpu_list_id)
3023fc9c5412SJohannes Schauer         cpu_list_id(stdout, &fprintf, "");
3024fc9c5412SJohannes Schauer #elif defined(cpu_list)
3025fc9c5412SJohannes Schauer         cpu_list(stdout, &fprintf); /* deprecated */
3026fc9c5412SJohannes Schauer #endif
3027fc9c5412SJohannes Schauer         exit(1);
3028fc9c5412SJohannes Schauer     }
3029fc9c5412SJohannes Schauer }
3030fc9c5412SJohannes Schauer 
3031fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE)
3032fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
3033fc9c5412SJohannes Schauer {
3034fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
3035fc9c5412SJohannes Schauer     have_guest_base = 1;
3036fc9c5412SJohannes Schauer }
3037fc9c5412SJohannes Schauer 
3038fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
3039fc9c5412SJohannes Schauer {
3040fc9c5412SJohannes Schauer     char *p;
3041fc9c5412SJohannes Schauer     int shift = 0;
3042fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
3043fc9c5412SJohannes Schauer     switch (*p) {
3044fc9c5412SJohannes Schauer     case 'k':
3045fc9c5412SJohannes Schauer     case 'K':
3046fc9c5412SJohannes Schauer         shift = 10;
3047fc9c5412SJohannes Schauer         break;
3048fc9c5412SJohannes Schauer     case 'M':
3049fc9c5412SJohannes Schauer         shift = 20;
3050fc9c5412SJohannes Schauer         break;
3051fc9c5412SJohannes Schauer     case 'G':
3052fc9c5412SJohannes Schauer         shift = 30;
3053fc9c5412SJohannes Schauer         break;
3054fc9c5412SJohannes Schauer     }
3055fc9c5412SJohannes Schauer     if (shift) {
3056fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
3057fc9c5412SJohannes Schauer         p++;
3058fc9c5412SJohannes Schauer         reserved_va <<= shift;
3059fc9c5412SJohannes Schauer         if (((reserved_va >> shift) != unshifted)
3060fc9c5412SJohannes Schauer #if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
3061fc9c5412SJohannes Schauer             || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
3062fc9c5412SJohannes Schauer #endif
3063fc9c5412SJohannes Schauer             ) {
3064fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
3065fc9c5412SJohannes Schauer             exit(1);
3066fc9c5412SJohannes Schauer         }
3067fc9c5412SJohannes Schauer     }
3068fc9c5412SJohannes Schauer     if (*p) {
3069fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
3070fc9c5412SJohannes Schauer         exit(1);
3071fc9c5412SJohannes Schauer     }
3072fc9c5412SJohannes Schauer }
3073fc9c5412SJohannes Schauer #endif
3074fc9c5412SJohannes Schauer 
3075fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
3076fc9c5412SJohannes Schauer {
3077fc9c5412SJohannes Schauer     singlestep = 1;
3078fc9c5412SJohannes Schauer }
3079fc9c5412SJohannes Schauer 
3080fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
3081fc9c5412SJohannes Schauer {
3082fc9c5412SJohannes Schauer     do_strace = 1;
3083fc9c5412SJohannes Schauer }
3084fc9c5412SJohannes Schauer 
3085fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
3086fc9c5412SJohannes Schauer {
3087fc9c5412SJohannes Schauer     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
3088fc9c5412SJohannes Schauer            ", Copyright (c) 2003-2008 Fabrice Bellard\n");
30891386d4c0SPeter Maydell     exit(0);
3090fc9c5412SJohannes Schauer }
3091fc9c5412SJohannes Schauer 
3092fc9c5412SJohannes Schauer struct qemu_argument {
3093fc9c5412SJohannes Schauer     const char *argv;
3094fc9c5412SJohannes Schauer     const char *env;
3095fc9c5412SJohannes Schauer     bool has_arg;
3096fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
3097fc9c5412SJohannes Schauer     const char *example;
3098fc9c5412SJohannes Schauer     const char *help;
3099fc9c5412SJohannes Schauer };
3100fc9c5412SJohannes Schauer 
3101fc9c5412SJohannes Schauer struct qemu_argument arg_table[] = {
3102fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
3103fc9c5412SJohannes Schauer      "",           "print this help"},
3104fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
3105fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
3106fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
3107fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
3108fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
3109fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
3110fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
3111fc9c5412SJohannes Schauer      "model",      "select CPU (-cpu ? for list)"},
3112fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
3113fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
3114fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
3115fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
3116fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
3117fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
3118fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
3119fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
3120fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE)
3121fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
3122fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
3123fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
3124fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
3125fc9c5412SJohannes Schauer #endif
3126fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
3127fc9c5412SJohannes Schauer      "options",    "activate log"},
3128fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
3129fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
3130fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
3131fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
3132fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
3133fc9c5412SJohannes Schauer      "",           "log system calls"},
3134fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
31351386d4c0SPeter Maydell      "",           "display version information and exit"},
3136fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
3137fc9c5412SJohannes Schauer };
3138fc9c5412SJohannes Schauer 
3139fc9c5412SJohannes Schauer static void usage(void)
3140fc9c5412SJohannes Schauer {
3141fc9c5412SJohannes Schauer     struct qemu_argument *arginfo;
3142fc9c5412SJohannes Schauer     int maxarglen;
3143fc9c5412SJohannes Schauer     int maxenvlen;
3144fc9c5412SJohannes Schauer 
3145fc9c5412SJohannes Schauer     printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
3146fc9c5412SJohannes Schauer            "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
3147fc9c5412SJohannes Schauer            "\n"
3148fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
3149fc9c5412SJohannes Schauer            "\n");
3150fc9c5412SJohannes Schauer 
3151fc9c5412SJohannes Schauer     maxarglen = maxenvlen = 0;
3152fc9c5412SJohannes Schauer 
3153fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3154fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
3155fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
3156fc9c5412SJohannes Schauer         }
3157fc9c5412SJohannes Schauer         if (strlen(arginfo->argv) > maxarglen) {
3158fc9c5412SJohannes Schauer             maxarglen = strlen(arginfo->argv);
3159fc9c5412SJohannes Schauer         }
3160fc9c5412SJohannes Schauer     }
3161fc9c5412SJohannes Schauer 
3162fc9c5412SJohannes Schauer     printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
3163fc9c5412SJohannes Schauer             maxenvlen+1, "Env-variable");
3164fc9c5412SJohannes Schauer 
3165fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3166fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
3167fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
3168fc9c5412SJohannes Schauer                     (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
3169fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env, arginfo->help);
3170fc9c5412SJohannes Schauer         } else {
3171fc9c5412SJohannes Schauer             printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
3172fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
3173fc9c5412SJohannes Schauer                     arginfo->help);
3174fc9c5412SJohannes Schauer         }
3175fc9c5412SJohannes Schauer     }
3176fc9c5412SJohannes Schauer 
3177fc9c5412SJohannes Schauer     printf("\n"
3178fc9c5412SJohannes Schauer            "Defaults:\n"
3179fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
3180fc9c5412SJohannes Schauer            "QEMU_STACK_SIZE = %ld byte\n"
3181fc9c5412SJohannes Schauer            "QEMU_LOG        = %s\n",
3182fc9c5412SJohannes Schauer            interp_prefix,
3183fc9c5412SJohannes Schauer            guest_stack_size,
3184fc9c5412SJohannes Schauer            DEBUG_LOGFILE);
3185fc9c5412SJohannes Schauer 
3186fc9c5412SJohannes Schauer     printf("\n"
3187fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
3188fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
3189fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
3190fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
3191fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
3192fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
3193fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
3194fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
3195fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
3196fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
3197fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
3198fc9c5412SJohannes Schauer            "the last change will stay in effect.\n");
3199fc9c5412SJohannes Schauer 
3200fc9c5412SJohannes Schauer     exit(1);
3201fc9c5412SJohannes Schauer }
3202fc9c5412SJohannes Schauer 
3203fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
3204fc9c5412SJohannes Schauer {
3205fc9c5412SJohannes Schauer     const char *r;
3206fc9c5412SJohannes Schauer     int optind;
3207fc9c5412SJohannes Schauer     struct qemu_argument *arginfo;
3208fc9c5412SJohannes Schauer 
3209fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3210fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
3211fc9c5412SJohannes Schauer             continue;
3212fc9c5412SJohannes Schauer         }
3213fc9c5412SJohannes Schauer 
3214fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
3215fc9c5412SJohannes Schauer         if (r != NULL) {
3216fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
3217fc9c5412SJohannes Schauer         }
3218fc9c5412SJohannes Schauer     }
3219fc9c5412SJohannes Schauer 
3220fc9c5412SJohannes Schauer     optind = 1;
3221fc9c5412SJohannes Schauer     for (;;) {
3222fc9c5412SJohannes Schauer         if (optind >= argc) {
3223fc9c5412SJohannes Schauer             break;
3224fc9c5412SJohannes Schauer         }
3225fc9c5412SJohannes Schauer         r = argv[optind];
3226fc9c5412SJohannes Schauer         if (r[0] != '-') {
3227fc9c5412SJohannes Schauer             break;
3228fc9c5412SJohannes Schauer         }
3229fc9c5412SJohannes Schauer         optind++;
3230fc9c5412SJohannes Schauer         r++;
3231fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
3232fc9c5412SJohannes Schauer             break;
3233fc9c5412SJohannes Schauer         }
3234fc9c5412SJohannes Schauer 
3235fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
3236fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
32371386d4c0SPeter Maydell                 if (arginfo->has_arg) {
3238fc9c5412SJohannes Schauer                     if (optind >= argc) {
3239fc9c5412SJohannes Schauer                         usage();
3240fc9c5412SJohannes Schauer                     }
3241fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
3242fc9c5412SJohannes Schauer                     optind++;
32431386d4c0SPeter Maydell                 } else {
32441386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
3245fc9c5412SJohannes Schauer                 }
3246fc9c5412SJohannes Schauer                 break;
3247fc9c5412SJohannes Schauer             }
3248fc9c5412SJohannes Schauer         }
3249fc9c5412SJohannes Schauer 
3250fc9c5412SJohannes Schauer         /* no option matched the current argv */
3251fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
3252fc9c5412SJohannes Schauer             usage();
3253fc9c5412SJohannes Schauer         }
3254fc9c5412SJohannes Schauer     }
3255fc9c5412SJohannes Schauer 
3256fc9c5412SJohannes Schauer     if (optind >= argc) {
3257fc9c5412SJohannes Schauer         usage();
3258fc9c5412SJohannes Schauer     }
3259fc9c5412SJohannes Schauer 
3260fc9c5412SJohannes Schauer     filename = argv[optind];
3261fc9c5412SJohannes Schauer     exec_path = argv[optind];
3262fc9c5412SJohannes Schauer 
3263fc9c5412SJohannes Schauer     return optind;
3264fc9c5412SJohannes Schauer }
3265fc9c5412SJohannes Schauer 
3266902b3d5cSmalc int main(int argc, char **argv, char **envp)
326731e31b8aSbellard {
3268c235d738SMatthew Fernandez     const char *log_file = DEBUG_LOGFILE;
326901ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
327031e31b8aSbellard     struct image_info info1, *info = &info1;
3271edf8e2afSMika Westerberg     struct linux_binprm bprm;
327248e15fc2SNathan Froyd     TaskState *ts;
3273b346ff46Sbellard     CPUState *env;
3274586314f2Sbellard     int optind;
327504a6dfebSaurel32     char **target_environ, **wrk;
32767d8cec95Saurel32     char **target_argv;
32777d8cec95Saurel32     int target_argc;
32787d8cec95Saurel32     int i;
3279fd4d81ddSArnaud Patard     int ret;
328031e31b8aSbellard 
3281902b3d5cSmalc     qemu_cache_utils_init(envp);
3282902b3d5cSmalc 
328304a6dfebSaurel32     if ((envlist = envlist_create()) == NULL) {
328404a6dfebSaurel32         (void) fprintf(stderr, "Unable to allocate envlist\n");
328504a6dfebSaurel32         exit(1);
328604a6dfebSaurel32     }
328704a6dfebSaurel32 
328804a6dfebSaurel32     /* add current environment into the list */
328904a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
329004a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
329104a6dfebSaurel32     }
329204a6dfebSaurel32 
3293703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
3294703e0e89SRichard Henderson        then we can do little else besides use the default.  */
3295703e0e89SRichard Henderson     {
3296703e0e89SRichard Henderson         struct rlimit lim;
3297703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
329881bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
329981bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur == (target_long)lim.rlim_cur) {
3300703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
3301703e0e89SRichard Henderson         }
3302703e0e89SRichard Henderson     }
3303703e0e89SRichard Henderson 
3304b1f9be31Sj_mayer     cpu_model = NULL;
3305b5ec5ce0Sjohn cooper #if defined(cpudef_setup)
3306b5ec5ce0Sjohn cooper     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
3307b5ec5ce0Sjohn cooper #endif
3308b5ec5ce0Sjohn cooper 
3309c235d738SMatthew Fernandez     /* init debug */
3310c235d738SMatthew Fernandez     cpu_set_log_filename(log_file);
3311fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
33124b5dfd82SPeter Maydell 
331331e31b8aSbellard     /* Zero out regs */
331401ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
331531e31b8aSbellard 
331631e31b8aSbellard     /* Zero out image_info */
331731e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
331831e31b8aSbellard 
3319edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
3320edf8e2afSMika Westerberg 
332174cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
332274cd30b8Sbellard     init_paths(interp_prefix);
332374cd30b8Sbellard 
332446027c07Sbellard     if (cpu_model == NULL) {
3325aaed909aSbellard #if defined(TARGET_I386)
332646027c07Sbellard #ifdef TARGET_X86_64
332746027c07Sbellard         cpu_model = "qemu64";
332846027c07Sbellard #else
332946027c07Sbellard         cpu_model = "qemu32";
333046027c07Sbellard #endif
3331aaed909aSbellard #elif defined(TARGET_ARM)
3332088ab16cSpbrook         cpu_model = "any";
3333d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
3334d2fbca94SGuan Xuetao         cpu_model = "any";
3335aaed909aSbellard #elif defined(TARGET_M68K)
3336aaed909aSbellard         cpu_model = "any";
3337aaed909aSbellard #elif defined(TARGET_SPARC)
3338aaed909aSbellard #ifdef TARGET_SPARC64
3339aaed909aSbellard         cpu_model = "TI UltraSparc II";
3340aaed909aSbellard #else
3341aaed909aSbellard         cpu_model = "Fujitsu MB86904";
334246027c07Sbellard #endif
3343aaed909aSbellard #elif defined(TARGET_MIPS)
3344aaed909aSbellard #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
3345aaed909aSbellard         cpu_model = "20Kc";
3346aaed909aSbellard #else
3347aaed909aSbellard         cpu_model = "24Kf";
3348aaed909aSbellard #endif
3349aaed909aSbellard #elif defined(TARGET_PPC)
33507ded4f52Sbellard #ifdef TARGET_PPC64
3351f7177937SAurelien Jarno         cpu_model = "970fx";
33527ded4f52Sbellard #else
3353aaed909aSbellard         cpu_model = "750";
33547ded4f52Sbellard #endif
3355aaed909aSbellard #else
3356aaed909aSbellard         cpu_model = "any";
3357aaed909aSbellard #endif
3358aaed909aSbellard     }
3359d5ab9713SJan Kiszka     tcg_exec_init(0);
3360d5ab9713SJan Kiszka     cpu_exec_init_all();
336183fb7adfSbellard     /* NOTE: we need to init the CPU at this stage to get
336283fb7adfSbellard        qemu_host_page_size */
3363aaed909aSbellard     env = cpu_init(cpu_model);
3364aaed909aSbellard     if (!env) {
3365aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
3366aaed909aSbellard         exit(1);
3367aaed909aSbellard     }
3368b55a37c9SBlue Swirl #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
3369b55a37c9SBlue Swirl     cpu_reset(env);
3370b55a37c9SBlue Swirl #endif
3371b55a37c9SBlue Swirl 
3372d5975363Spbrook     thread_env = env;
337354936004Sbellard 
3374b92c47c1Sths     if (getenv("QEMU_STRACE")) {
3375b92c47c1Sths         do_strace = 1;
3376b92c47c1Sths     }
3377b92c47c1Sths 
337804a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
337904a6dfebSaurel32     envlist_free(envlist);
3380b12b6a18Sths 
3381379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
3382379f6698SPaul Brook     /*
3383379f6698SPaul Brook      * Now that page sizes are configured in cpu_init() we can do
3384379f6698SPaul Brook      * proper page alignment for guest_base.
3385379f6698SPaul Brook      */
3386379f6698SPaul Brook     guest_base = HOST_PAGE_ALIGN(guest_base);
338768a1c816SPaul Brook 
338868a1c816SPaul Brook     if (reserved_va) {
338968a1c816SPaul Brook         void *p;
339068a1c816SPaul Brook         int flags;
339168a1c816SPaul Brook 
339268a1c816SPaul Brook         flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
339368a1c816SPaul Brook         if (have_guest_base) {
339468a1c816SPaul Brook             flags |= MAP_FIXED;
339568a1c816SPaul Brook         }
339668a1c816SPaul Brook         p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0);
339768a1c816SPaul Brook         if (p == MAP_FAILED) {
339868a1c816SPaul Brook             fprintf(stderr, "Unable to reserve guest address space\n");
339968a1c816SPaul Brook             exit(1);
340068a1c816SPaul Brook         }
340168a1c816SPaul Brook         guest_base = (unsigned long)p;
340268a1c816SPaul Brook         /* Make sure the address is properly aligned.  */
340368a1c816SPaul Brook         if (guest_base & ~qemu_host_page_mask) {
340468a1c816SPaul Brook             munmap(p, reserved_va);
340568a1c816SPaul Brook             p = mmap((void *)guest_base, reserved_va + qemu_host_page_size,
340668a1c816SPaul Brook                      PROT_NONE, flags, -1, 0);
340768a1c816SPaul Brook             if (p == MAP_FAILED) {
340868a1c816SPaul Brook                 fprintf(stderr, "Unable to reserve guest address space\n");
340968a1c816SPaul Brook                 exit(1);
341068a1c816SPaul Brook             }
341168a1c816SPaul Brook             guest_base = HOST_PAGE_ALIGN((unsigned long)p);
341268a1c816SPaul Brook         }
341368a1c816SPaul Brook         qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
341468a1c816SPaul Brook     }
341597cc7560SDr. David Alan Gilbert 
341697cc7560SDr. David Alan Gilbert     if (reserved_va || have_guest_base) {
341797cc7560SDr. David Alan Gilbert         if (!guest_validate_base(guest_base)) {
341897cc7560SDr. David Alan Gilbert             fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
341997cc7560SDr. David Alan Gilbert             exit(1);
342097cc7560SDr. David Alan Gilbert         }
342197cc7560SDr. David Alan Gilbert     }
342214f24e14SRichard Henderson #endif /* CONFIG_USE_GUEST_BASE */
3423379f6698SPaul Brook 
3424379f6698SPaul Brook     /*
3425379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
3426379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
342714f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
3428379f6698SPaul Brook      */
342914f24e14SRichard Henderson     {
3430379f6698SPaul Brook         FILE *fp;
3431379f6698SPaul Brook 
3432379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
3433379f6698SPaul Brook             unsigned long tmp;
3434379f6698SPaul Brook             if (fscanf(fp, "%lu", &tmp) == 1) {
3435379f6698SPaul Brook                 mmap_min_addr = tmp;
3436379f6698SPaul Brook                 qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
3437379f6698SPaul Brook             }
3438379f6698SPaul Brook             fclose(fp);
3439379f6698SPaul Brook         }
3440379f6698SPaul Brook     }
3441379f6698SPaul Brook 
34427d8cec95Saurel32     /*
34437d8cec95Saurel32      * Prepare copy of argv vector for target.
34447d8cec95Saurel32      */
34457d8cec95Saurel32     target_argc = argc - optind;
34467d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
34477d8cec95Saurel32     if (target_argv == NULL) {
34487d8cec95Saurel32 	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
34497d8cec95Saurel32 	exit(1);
34507d8cec95Saurel32     }
34517d8cec95Saurel32 
34527d8cec95Saurel32     /*
34537d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
34547d8cec95Saurel32      * argv[0] pointer with the given one.
34557d8cec95Saurel32      */
34567d8cec95Saurel32     i = 0;
34577d8cec95Saurel32     if (argv0 != NULL) {
34587d8cec95Saurel32         target_argv[i++] = strdup(argv0);
34597d8cec95Saurel32     }
34607d8cec95Saurel32     for (; i < target_argc; i++) {
34617d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
34627d8cec95Saurel32     }
34637d8cec95Saurel32     target_argv[target_argc] = NULL;
34647d8cec95Saurel32 
34657267c094SAnthony Liguori     ts = g_malloc0 (sizeof(TaskState));
3466edf8e2afSMika Westerberg     init_task_state(ts);
3467edf8e2afSMika Westerberg     /* build Task State */
3468edf8e2afSMika Westerberg     ts->info = info;
3469edf8e2afSMika Westerberg     ts->bprm = &bprm;
3470edf8e2afSMika Westerberg     env->opaque = ts;
3471edf8e2afSMika Westerberg     task_settid(ts);
3472edf8e2afSMika Westerberg 
3473fd4d81ddSArnaud Patard     ret = loader_exec(filename, target_argv, target_environ, regs,
3474fd4d81ddSArnaud Patard         info, &bprm);
3475fd4d81ddSArnaud Patard     if (ret != 0) {
3476fd4d81ddSArnaud Patard         printf("Error %d while loading %s\n", ret, filename);
347774cd30b8Sbellard         _exit(1);
347831e31b8aSbellard     }
347931e31b8aSbellard 
34807d8cec95Saurel32     for (i = 0; i < target_argc; i++) {
34817d8cec95Saurel32         free(target_argv[i]);
34827d8cec95Saurel32     }
34837d8cec95Saurel32     free(target_argv);
34847d8cec95Saurel32 
3485b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
3486b12b6a18Sths         free(*wrk);
3487b12b6a18Sths     }
3488b12b6a18Sths 
3489b12b6a18Sths     free(target_environ);
3490b12b6a18Sths 
34912e77eac6Sblueswir1     if (qemu_log_enabled()) {
3492379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE)
3493379f6698SPaul Brook         qemu_log("guest_base  0x%lx\n", guest_base);
3494379f6698SPaul Brook #endif
349593fcfe39Saliguori         log_page_dump();
349654936004Sbellard 
349793fcfe39Saliguori         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
349893fcfe39Saliguori         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
349993fcfe39Saliguori         qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
35003d177870Sj_mayer                  info->start_code);
350193fcfe39Saliguori         qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
35023d177870Sj_mayer                  info->start_data);
350393fcfe39Saliguori         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
350493fcfe39Saliguori         qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
35053d177870Sj_mayer                  info->start_stack);
350693fcfe39Saliguori         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
350793fcfe39Saliguori         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
35082e77eac6Sblueswir1     }
350931e31b8aSbellard 
351053a5960aSpbrook     target_set_brk(info->brk);
351131e31b8aSbellard     syscall_init();
351266fb9763Sbellard     signal_init();
351331e31b8aSbellard 
35149002ec79SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE)
35159002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
35169002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
35179002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
35189002ec79SRichard Henderson     tcg_prologue_init(&tcg_ctx);
35199002ec79SRichard Henderson #endif
35209002ec79SRichard Henderson 
3521b346ff46Sbellard #if defined(TARGET_I386)
35222e255c6bSbellard     cpu_x86_set_cpl(env, 3);
35232e255c6bSbellard 
35243802ce26Sbellard     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
35251bde465eSbellard     env->hflags |= HF_PE_MASK;
35261bde465eSbellard     if (env->cpuid_features & CPUID_SSE) {
35271bde465eSbellard         env->cr[4] |= CR4_OSFXSR_MASK;
35281bde465eSbellard         env->hflags |= HF_OSFXSR_MASK;
35291bde465eSbellard     }
3530d2fd1af7Sbellard #ifndef TARGET_ABI32
35314dbc422bSbellard     /* enable 64 bit mode if possible */
35324dbc422bSbellard     if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
35334dbc422bSbellard         fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
35344dbc422bSbellard         exit(1);
35354dbc422bSbellard     }
3536d2fd1af7Sbellard     env->cr[4] |= CR4_PAE_MASK;
35374dbc422bSbellard     env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
3538d2fd1af7Sbellard     env->hflags |= HF_LMA_MASK;
3539d2fd1af7Sbellard #endif
35403802ce26Sbellard 
3541415e561fSbellard     /* flags setup : we activate the IRQs by default as in user mode */
3542415e561fSbellard     env->eflags |= IF_MASK;
3543415e561fSbellard 
35446dbad63eSbellard     /* linux register setup */
3545d2fd1af7Sbellard #ifndef TARGET_ABI32
354684409ddbSj_mayer     env->regs[R_EAX] = regs->rax;
354784409ddbSj_mayer     env->regs[R_EBX] = regs->rbx;
354884409ddbSj_mayer     env->regs[R_ECX] = regs->rcx;
354984409ddbSj_mayer     env->regs[R_EDX] = regs->rdx;
355084409ddbSj_mayer     env->regs[R_ESI] = regs->rsi;
355184409ddbSj_mayer     env->regs[R_EDI] = regs->rdi;
355284409ddbSj_mayer     env->regs[R_EBP] = regs->rbp;
355384409ddbSj_mayer     env->regs[R_ESP] = regs->rsp;
355484409ddbSj_mayer     env->eip = regs->rip;
355584409ddbSj_mayer #else
35560ecfa993Sbellard     env->regs[R_EAX] = regs->eax;
35570ecfa993Sbellard     env->regs[R_EBX] = regs->ebx;
35580ecfa993Sbellard     env->regs[R_ECX] = regs->ecx;
35590ecfa993Sbellard     env->regs[R_EDX] = regs->edx;
35600ecfa993Sbellard     env->regs[R_ESI] = regs->esi;
35610ecfa993Sbellard     env->regs[R_EDI] = regs->edi;
35620ecfa993Sbellard     env->regs[R_EBP] = regs->ebp;
35630ecfa993Sbellard     env->regs[R_ESP] = regs->esp;
3564dab2ed99Sbellard     env->eip = regs->eip;
356584409ddbSj_mayer #endif
356631e31b8aSbellard 
3567f4beb510Sbellard     /* linux interrupt setup */
3568e441570fSbalrog #ifndef TARGET_ABI32
3569e441570fSbalrog     env->idt.limit = 511;
3570e441570fSbalrog #else
3571e441570fSbalrog     env->idt.limit = 255;
3572e441570fSbalrog #endif
3573e441570fSbalrog     env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
3574e441570fSbalrog                                 PROT_READ|PROT_WRITE,
3575e441570fSbalrog                                 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
3576e441570fSbalrog     idt_table = g2h(env->idt.base);
3577f4beb510Sbellard     set_idt(0, 0);
3578f4beb510Sbellard     set_idt(1, 0);
3579f4beb510Sbellard     set_idt(2, 0);
3580f4beb510Sbellard     set_idt(3, 3);
3581f4beb510Sbellard     set_idt(4, 3);
3582ec95da6cSbellard     set_idt(5, 0);
3583f4beb510Sbellard     set_idt(6, 0);
3584f4beb510Sbellard     set_idt(7, 0);
3585f4beb510Sbellard     set_idt(8, 0);
3586f4beb510Sbellard     set_idt(9, 0);
3587f4beb510Sbellard     set_idt(10, 0);
3588f4beb510Sbellard     set_idt(11, 0);
3589f4beb510Sbellard     set_idt(12, 0);
3590f4beb510Sbellard     set_idt(13, 0);
3591f4beb510Sbellard     set_idt(14, 0);
3592f4beb510Sbellard     set_idt(15, 0);
3593f4beb510Sbellard     set_idt(16, 0);
3594f4beb510Sbellard     set_idt(17, 0);
3595f4beb510Sbellard     set_idt(18, 0);
3596f4beb510Sbellard     set_idt(19, 0);
3597f4beb510Sbellard     set_idt(0x80, 3);
3598f4beb510Sbellard 
35996dbad63eSbellard     /* linux segment setup */
36008d18e893Sbellard     {
36018d18e893Sbellard         uint64_t *gdt_table;
3602e441570fSbalrog         env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
3603e441570fSbalrog                                     PROT_READ|PROT_WRITE,
3604e441570fSbalrog                                     MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
36058d18e893Sbellard         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
3606e441570fSbalrog         gdt_table = g2h(env->gdt.base);
3607d2fd1af7Sbellard #ifdef TARGET_ABI32
3608f4beb510Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
3609f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3610f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
3611d2fd1af7Sbellard #else
3612d2fd1af7Sbellard         /* 64 bit code segment */
3613d2fd1af7Sbellard         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
3614d2fd1af7Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3615d2fd1af7Sbellard                  DESC_L_MASK |
3616d2fd1af7Sbellard                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
3617d2fd1af7Sbellard #endif
3618f4beb510Sbellard         write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
3619f4beb510Sbellard                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
3620f4beb510Sbellard                  (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
36218d18e893Sbellard     }
36226dbad63eSbellard     cpu_x86_load_seg(env, R_CS, __USER_CS);
3623d2fd1af7Sbellard     cpu_x86_load_seg(env, R_SS, __USER_DS);
3624d2fd1af7Sbellard #ifdef TARGET_ABI32
36256dbad63eSbellard     cpu_x86_load_seg(env, R_DS, __USER_DS);
36266dbad63eSbellard     cpu_x86_load_seg(env, R_ES, __USER_DS);
36276dbad63eSbellard     cpu_x86_load_seg(env, R_FS, __USER_DS);
36286dbad63eSbellard     cpu_x86_load_seg(env, R_GS, __USER_DS);
3629d6eb40f6Sths     /* This hack makes Wine work... */
3630d6eb40f6Sths     env->segs[R_FS].selector = 0;
3631d2fd1af7Sbellard #else
3632d2fd1af7Sbellard     cpu_x86_load_seg(env, R_DS, 0);
3633d2fd1af7Sbellard     cpu_x86_load_seg(env, R_ES, 0);
3634d2fd1af7Sbellard     cpu_x86_load_seg(env, R_FS, 0);
3635d2fd1af7Sbellard     cpu_x86_load_seg(env, R_GS, 0);
3636d2fd1af7Sbellard #endif
3637b346ff46Sbellard #elif defined(TARGET_ARM)
3638b346ff46Sbellard     {
3639b346ff46Sbellard         int i;
3640b5ff1b31Sbellard         cpsr_write(env, regs->uregs[16], 0xffffffff);
3641b346ff46Sbellard         for(i = 0; i < 16; i++) {
3642b346ff46Sbellard             env->regs[i] = regs->uregs[i];
3643b346ff46Sbellard         }
3644b346ff46Sbellard     }
3645d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32)
3646d2fbca94SGuan Xuetao     {
3647d2fbca94SGuan Xuetao         int i;
3648d2fbca94SGuan Xuetao         cpu_asr_write(env, regs->uregs[32], 0xffffffff);
3649d2fbca94SGuan Xuetao         for (i = 0; i < 32; i++) {
3650d2fbca94SGuan Xuetao             env->regs[i] = regs->uregs[i];
3651d2fbca94SGuan Xuetao         }
3652d2fbca94SGuan Xuetao     }
365393ac68bcSbellard #elif defined(TARGET_SPARC)
3654060366c5Sbellard     {
3655060366c5Sbellard         int i;
3656060366c5Sbellard 	env->pc = regs->pc;
3657060366c5Sbellard 	env->npc = regs->npc;
3658060366c5Sbellard         env->y = regs->y;
3659060366c5Sbellard         for(i = 0; i < 8; i++)
3660060366c5Sbellard             env->gregs[i] = regs->u_regs[i];
3661060366c5Sbellard         for(i = 0; i < 8; i++)
3662060366c5Sbellard             env->regwptr[i] = regs->u_regs[i + 8];
3663060366c5Sbellard     }
366467867308Sbellard #elif defined(TARGET_PPC)
366567867308Sbellard     {
366667867308Sbellard         int i;
36673fc6c082Sbellard 
36680411a972Sj_mayer #if defined(TARGET_PPC64)
36690411a972Sj_mayer #if defined(TARGET_ABI32)
36700411a972Sj_mayer         env->msr &= ~((target_ulong)1 << MSR_SF);
3671e85e7c6eSj_mayer #else
36720411a972Sj_mayer         env->msr |= (target_ulong)1 << MSR_SF;
36730411a972Sj_mayer #endif
367484409ddbSj_mayer #endif
367567867308Sbellard         env->nip = regs->nip;
367667867308Sbellard         for(i = 0; i < 32; i++) {
367767867308Sbellard             env->gpr[i] = regs->gpr[i];
367867867308Sbellard         }
367967867308Sbellard     }
3680e6e5906bSpbrook #elif defined(TARGET_M68K)
3681e6e5906bSpbrook     {
3682e6e5906bSpbrook         env->pc = regs->pc;
3683e6e5906bSpbrook         env->dregs[0] = regs->d0;
3684e6e5906bSpbrook         env->dregs[1] = regs->d1;
3685e6e5906bSpbrook         env->dregs[2] = regs->d2;
3686e6e5906bSpbrook         env->dregs[3] = regs->d3;
3687e6e5906bSpbrook         env->dregs[4] = regs->d4;
3688e6e5906bSpbrook         env->dregs[5] = regs->d5;
3689e6e5906bSpbrook         env->dregs[6] = regs->d6;
3690e6e5906bSpbrook         env->dregs[7] = regs->d7;
3691e6e5906bSpbrook         env->aregs[0] = regs->a0;
3692e6e5906bSpbrook         env->aregs[1] = regs->a1;
3693e6e5906bSpbrook         env->aregs[2] = regs->a2;
3694e6e5906bSpbrook         env->aregs[3] = regs->a3;
3695e6e5906bSpbrook         env->aregs[4] = regs->a4;
3696e6e5906bSpbrook         env->aregs[5] = regs->a5;
3697e6e5906bSpbrook         env->aregs[6] = regs->a6;
3698e6e5906bSpbrook         env->aregs[7] = regs->usp;
3699e6e5906bSpbrook         env->sr = regs->sr;
3700e6e5906bSpbrook         ts->sim_syscalls = 1;
3701e6e5906bSpbrook     }
3702b779e29eSEdgar E. Iglesias #elif defined(TARGET_MICROBLAZE)
3703b779e29eSEdgar E. Iglesias     {
3704b779e29eSEdgar E. Iglesias         env->regs[0] = regs->r0;
3705b779e29eSEdgar E. Iglesias         env->regs[1] = regs->r1;
3706b779e29eSEdgar E. Iglesias         env->regs[2] = regs->r2;
3707b779e29eSEdgar E. Iglesias         env->regs[3] = regs->r3;
3708b779e29eSEdgar E. Iglesias         env->regs[4] = regs->r4;
3709b779e29eSEdgar E. Iglesias         env->regs[5] = regs->r5;
3710b779e29eSEdgar E. Iglesias         env->regs[6] = regs->r6;
3711b779e29eSEdgar E. Iglesias         env->regs[7] = regs->r7;
3712b779e29eSEdgar E. Iglesias         env->regs[8] = regs->r8;
3713b779e29eSEdgar E. Iglesias         env->regs[9] = regs->r9;
3714b779e29eSEdgar E. Iglesias         env->regs[10] = regs->r10;
3715b779e29eSEdgar E. Iglesias         env->regs[11] = regs->r11;
3716b779e29eSEdgar E. Iglesias         env->regs[12] = regs->r12;
3717b779e29eSEdgar E. Iglesias         env->regs[13] = regs->r13;
3718b779e29eSEdgar E. Iglesias         env->regs[14] = regs->r14;
3719b779e29eSEdgar E. Iglesias         env->regs[15] = regs->r15;
3720b779e29eSEdgar E. Iglesias         env->regs[16] = regs->r16;
3721b779e29eSEdgar E. Iglesias         env->regs[17] = regs->r17;
3722b779e29eSEdgar E. Iglesias         env->regs[18] = regs->r18;
3723b779e29eSEdgar E. Iglesias         env->regs[19] = regs->r19;
3724b779e29eSEdgar E. Iglesias         env->regs[20] = regs->r20;
3725b779e29eSEdgar E. Iglesias         env->regs[21] = regs->r21;
3726b779e29eSEdgar E. Iglesias         env->regs[22] = regs->r22;
3727b779e29eSEdgar E. Iglesias         env->regs[23] = regs->r23;
3728b779e29eSEdgar E. Iglesias         env->regs[24] = regs->r24;
3729b779e29eSEdgar E. Iglesias         env->regs[25] = regs->r25;
3730b779e29eSEdgar E. Iglesias         env->regs[26] = regs->r26;
3731b779e29eSEdgar E. Iglesias         env->regs[27] = regs->r27;
3732b779e29eSEdgar E. Iglesias         env->regs[28] = regs->r28;
3733b779e29eSEdgar E. Iglesias         env->regs[29] = regs->r29;
3734b779e29eSEdgar E. Iglesias         env->regs[30] = regs->r30;
3735b779e29eSEdgar E. Iglesias         env->regs[31] = regs->r31;
3736b779e29eSEdgar E. Iglesias         env->sregs[SR_PC] = regs->pc;
3737b779e29eSEdgar E. Iglesias     }
3738048f6b4dSbellard #elif defined(TARGET_MIPS)
3739048f6b4dSbellard     {
3740048f6b4dSbellard         int i;
3741048f6b4dSbellard 
3742048f6b4dSbellard         for(i = 0; i < 32; i++) {
3743b5dc7732Sths             env->active_tc.gpr[i] = regs->regs[i];
3744048f6b4dSbellard         }
37450fddbbf2SNathan Froyd         env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
37460fddbbf2SNathan Froyd         if (regs->cp0_epc & 1) {
37470fddbbf2SNathan Froyd             env->hflags |= MIPS_HFLAG_M16;
37480fddbbf2SNathan Froyd         }
3749048f6b4dSbellard     }
3750fdf9b3e8Sbellard #elif defined(TARGET_SH4)
3751fdf9b3e8Sbellard     {
3752fdf9b3e8Sbellard         int i;
3753fdf9b3e8Sbellard 
3754fdf9b3e8Sbellard         for(i = 0; i < 16; i++) {
3755fdf9b3e8Sbellard             env->gregs[i] = regs->regs[i];
3756fdf9b3e8Sbellard         }
3757fdf9b3e8Sbellard         env->pc = regs->pc;
3758fdf9b3e8Sbellard     }
37597a3148a9Sj_mayer #elif defined(TARGET_ALPHA)
37607a3148a9Sj_mayer     {
37617a3148a9Sj_mayer         int i;
37627a3148a9Sj_mayer 
37637a3148a9Sj_mayer         for(i = 0; i < 28; i++) {
3764992f48a0Sblueswir1             env->ir[i] = ((abi_ulong *)regs)[i];
37657a3148a9Sj_mayer         }
3766dad081eeSRichard Henderson         env->ir[IR_SP] = regs->usp;
37677a3148a9Sj_mayer         env->pc = regs->pc;
37687a3148a9Sj_mayer     }
376948733d19Sths #elif defined(TARGET_CRIS)
377048733d19Sths     {
377148733d19Sths 	    env->regs[0] = regs->r0;
377248733d19Sths 	    env->regs[1] = regs->r1;
377348733d19Sths 	    env->regs[2] = regs->r2;
377448733d19Sths 	    env->regs[3] = regs->r3;
377548733d19Sths 	    env->regs[4] = regs->r4;
377648733d19Sths 	    env->regs[5] = regs->r5;
377748733d19Sths 	    env->regs[6] = regs->r6;
377848733d19Sths 	    env->regs[7] = regs->r7;
377948733d19Sths 	    env->regs[8] = regs->r8;
378048733d19Sths 	    env->regs[9] = regs->r9;
378148733d19Sths 	    env->regs[10] = regs->r10;
378248733d19Sths 	    env->regs[11] = regs->r11;
378348733d19Sths 	    env->regs[12] = regs->r12;
378448733d19Sths 	    env->regs[13] = regs->r13;
378548733d19Sths 	    env->regs[14] = info->start_stack;
378648733d19Sths 	    env->regs[15] = regs->acr;
378748733d19Sths 	    env->pc = regs->erp;
378848733d19Sths     }
3789a4c075f1SUlrich Hecht #elif defined(TARGET_S390X)
3790a4c075f1SUlrich Hecht     {
3791a4c075f1SUlrich Hecht             int i;
3792a4c075f1SUlrich Hecht             for (i = 0; i < 16; i++) {
3793a4c075f1SUlrich Hecht                 env->regs[i] = regs->gprs[i];
3794a4c075f1SUlrich Hecht             }
3795a4c075f1SUlrich Hecht             env->psw.mask = regs->psw.mask;
3796a4c075f1SUlrich Hecht             env->psw.addr = regs->psw.addr;
3797a4c075f1SUlrich Hecht     }
3798b346ff46Sbellard #else
3799b346ff46Sbellard #error unsupported target CPU
3800b346ff46Sbellard #endif
380131e31b8aSbellard 
3802d2fbca94SGuan Xuetao #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
3803a87295e8Spbrook     ts->stack_base = info->start_stack;
3804a87295e8Spbrook     ts->heap_base = info->brk;
3805a87295e8Spbrook     /* This will be filled in on the first SYS_HEAPINFO call.  */
3806a87295e8Spbrook     ts->heap_limit = 0;
3807a87295e8Spbrook #endif
3808a87295e8Spbrook 
380974c33bedSbellard     if (gdbstub_port) {
3810ff7a981aSPeter Maydell         if (gdbserver_start(gdbstub_port) < 0) {
3811ff7a981aSPeter Maydell             fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
3812ff7a981aSPeter Maydell                     gdbstub_port);
3813ff7a981aSPeter Maydell             exit(1);
3814ff7a981aSPeter Maydell         }
38151fddef4bSbellard         gdb_handlesig(env, 0);
38161fddef4bSbellard     }
38171b6b029eSbellard     cpu_loop(env);
38181b6b029eSbellard     /* never exits */
381931e31b8aSbellard     return 0;
382031e31b8aSbellard }
3821