xref: /qemu/linux-user/main.c (revision b1f9be31)
131e31b8aSbellard /*
293ac68bcSbellard  *  qemu user main
331e31b8aSbellard  *
431e31b8aSbellard  *  Copyright (c) 2003 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
1731e31b8aSbellard  *  along with this program; if not, write to the Free Software
1831e31b8aSbellard  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1931e31b8aSbellard  */
2031e31b8aSbellard #include <stdlib.h>
2131e31b8aSbellard #include <stdio.h>
2231e31b8aSbellard #include <stdarg.h>
2304369ff2Sbellard #include <string.h>
2431e31b8aSbellard #include <errno.h>
250ecfa993Sbellard #include <unistd.h>
2631e31b8aSbellard 
273ef693a0Sbellard #include "qemu.h"
2831e31b8aSbellard 
293ef693a0Sbellard #define DEBUG_LOGFILE "/tmp/qemu.log"
30586314f2Sbellard 
3183fb7adfSbellard #ifdef __APPLE__
3283fb7adfSbellard #include <crt_externs.h>
3383fb7adfSbellard # define environ  (*_NSGetEnviron())
3483fb7adfSbellard #endif
3583fb7adfSbellard 
3674cd30b8Sbellard static const char *interp_prefix = CONFIG_QEMU_PREFIX;
37c5937220Spbrook const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
38586314f2Sbellard 
393a4739d6Sbellard #if defined(__i386__) && !defined(CONFIG_STATIC)
40f801f97eSbellard /* Force usage of an ELF interpreter even if it is an ELF shared
41f801f97eSbellard    object ! */
42f801f97eSbellard const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
434304763bSbellard #endif
4474cd30b8Sbellard 
4593ac68bcSbellard /* for recent libc, we add these dummy symbols which are not declared
4674cd30b8Sbellard    when generating a linked object (bug in ld ?) */
47fbf59244Sbellard #if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)
48c6981055Sbellard long __preinit_array_start[0];
49c6981055Sbellard long __preinit_array_end[0];
5074cd30b8Sbellard long __init_array_start[0];
5174cd30b8Sbellard long __init_array_end[0];
5274cd30b8Sbellard long __fini_array_start[0];
5374cd30b8Sbellard long __fini_array_end[0];
5474cd30b8Sbellard #endif
5574cd30b8Sbellard 
569de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
579de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
589de5e440Sbellard    by remapping the process stack directly at the right place */
599de5e440Sbellard unsigned long x86_stack_size = 512 * 1024;
6031e31b8aSbellard 
6131e31b8aSbellard void gemu_log(const char *fmt, ...)
6231e31b8aSbellard {
6331e31b8aSbellard     va_list ap;
6431e31b8aSbellard 
6531e31b8aSbellard     va_start(ap, fmt);
6631e31b8aSbellard     vfprintf(stderr, fmt, ap);
6731e31b8aSbellard     va_end(ap);
6831e31b8aSbellard }
6931e31b8aSbellard 
7061190b14Sbellard void cpu_outb(CPUState *env, int addr, int val)
71367e86e8Sbellard {
72367e86e8Sbellard     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
73367e86e8Sbellard }
74367e86e8Sbellard 
7561190b14Sbellard void cpu_outw(CPUState *env, int addr, int val)
76367e86e8Sbellard {
77367e86e8Sbellard     fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
78367e86e8Sbellard }
79367e86e8Sbellard 
8061190b14Sbellard void cpu_outl(CPUState *env, int addr, int val)
81367e86e8Sbellard {
82367e86e8Sbellard     fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
83367e86e8Sbellard }
84367e86e8Sbellard 
8561190b14Sbellard int cpu_inb(CPUState *env, int addr)
86367e86e8Sbellard {
87367e86e8Sbellard     fprintf(stderr, "inb: port=0x%04x\n", addr);
88367e86e8Sbellard     return 0;
89367e86e8Sbellard }
90367e86e8Sbellard 
9161190b14Sbellard int cpu_inw(CPUState *env, int addr)
92367e86e8Sbellard {
93367e86e8Sbellard     fprintf(stderr, "inw: port=0x%04x\n", addr);
94367e86e8Sbellard     return 0;
95367e86e8Sbellard }
96367e86e8Sbellard 
9761190b14Sbellard int cpu_inl(CPUState *env, int addr)
98367e86e8Sbellard {
99367e86e8Sbellard     fprintf(stderr, "inl: port=0x%04x\n", addr);
100367e86e8Sbellard     return 0;
101367e86e8Sbellard }
102367e86e8Sbellard 
103a541f297Sbellard int cpu_get_pic_interrupt(CPUState *env)
10492ccca6aSbellard {
10592ccca6aSbellard     return -1;
10692ccca6aSbellard }
10792ccca6aSbellard 
10828ab0e2eSbellard /* timers for rdtsc */
10928ab0e2eSbellard 
1101dce7c3cSbellard #if 0
11128ab0e2eSbellard 
11228ab0e2eSbellard static uint64_t emu_time;
11328ab0e2eSbellard 
11428ab0e2eSbellard int64_t cpu_get_real_ticks(void)
11528ab0e2eSbellard {
11628ab0e2eSbellard     return emu_time++;
11728ab0e2eSbellard }
11828ab0e2eSbellard 
11928ab0e2eSbellard #endif
12028ab0e2eSbellard 
121a541f297Sbellard #ifdef TARGET_I386
122a541f297Sbellard /***********************************************************/
123a541f297Sbellard /* CPUX86 core interface */
124a541f297Sbellard 
12502a1602eSbellard void cpu_smm_update(CPUState *env)
12602a1602eSbellard {
12702a1602eSbellard }
12802a1602eSbellard 
12928ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env)
13028ab0e2eSbellard {
13128ab0e2eSbellard     return cpu_get_real_ticks();
13228ab0e2eSbellard }
13328ab0e2eSbellard 
134f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
135f4beb510Sbellard                      int flags)
1366dbad63eSbellard {
137f4beb510Sbellard     unsigned int e1, e2;
13853a5960aSpbrook     uint32_t *p;
1396dbad63eSbellard     e1 = (addr << 16) | (limit & 0xffff);
1406dbad63eSbellard     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
141f4beb510Sbellard     e2 |= flags;
14253a5960aSpbrook     p = ptr;
14353a5960aSpbrook     p[0] = tswapl(e1);
14453a5960aSpbrook     p[1] = tswapl(e2);
145f4beb510Sbellard }
146f4beb510Sbellard 
147f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
148f4beb510Sbellard                      unsigned long addr, unsigned int sel)
149f4beb510Sbellard {
150f4beb510Sbellard     unsigned int e1, e2;
15153a5960aSpbrook     uint32_t *p;
152f4beb510Sbellard     e1 = (addr & 0xffff) | (sel << 16);
153f4beb510Sbellard     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
15453a5960aSpbrook     p = ptr;
15553a5960aSpbrook     p[0] = tswapl(e1);
15653a5960aSpbrook     p[1] = tswapl(e2);
1576dbad63eSbellard }
1586dbad63eSbellard 
1596dbad63eSbellard uint64_t gdt_table[6];
160f4beb510Sbellard uint64_t idt_table[256];
161f4beb510Sbellard 
162f4beb510Sbellard /* only dpl matters as we do only user space emulation */
163f4beb510Sbellard static void set_idt(int n, unsigned int dpl)
164f4beb510Sbellard {
165f4beb510Sbellard     set_gate(idt_table + n, 0, dpl, 0, 0);
166f4beb510Sbellard }
16731e31b8aSbellard 
16889e957e7Sbellard void cpu_loop(CPUX86State *env)
169bc8a22ccSbellard {
170bc8a22ccSbellard     int trapnr;
17180a9d035Sbellard     target_ulong pc;
172bc8a22ccSbellard     target_siginfo_t info;
173bc8a22ccSbellard 
174bc8a22ccSbellard     for(;;) {
175bc8a22ccSbellard         trapnr = cpu_x86_exec(env);
176bc8a22ccSbellard         switch(trapnr) {
177f4beb510Sbellard         case 0x80:
178f4beb510Sbellard             /* linux syscall */
1791b6b029eSbellard             env->regs[R_EAX] = do_syscall(env,
1801b6b029eSbellard                                           env->regs[R_EAX],
1811b6b029eSbellard                                           env->regs[R_EBX],
1821b6b029eSbellard                                           env->regs[R_ECX],
1831b6b029eSbellard                                           env->regs[R_EDX],
1841b6b029eSbellard                                           env->regs[R_ESI],
1851b6b029eSbellard                                           env->regs[R_EDI],
1861b6b029eSbellard                                           env->regs[R_EBP]);
187f4beb510Sbellard             break;
188f4beb510Sbellard         case EXCP0B_NOSEG:
189f4beb510Sbellard         case EXCP0C_STACK:
190f4beb510Sbellard             info.si_signo = SIGBUS;
191f4beb510Sbellard             info.si_errno = 0;
192f4beb510Sbellard             info.si_code = TARGET_SI_KERNEL;
193f4beb510Sbellard             info._sifields._sigfault._addr = 0;
194f4beb510Sbellard             queue_signal(info.si_signo, &info);
195f4beb510Sbellard             break;
196f4beb510Sbellard         case EXCP0D_GPF:
197f4beb510Sbellard             if (env->eflags & VM_MASK) {
198f4beb510Sbellard                 handle_vm86_fault(env);
1991b6b029eSbellard             } else {
2009de5e440Sbellard                 info.si_signo = SIGSEGV;
2019de5e440Sbellard                 info.si_errno = 0;
202b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
2039de5e440Sbellard                 info._sifields._sigfault._addr = 0;
2049de5e440Sbellard                 queue_signal(info.si_signo, &info);
2051b6b029eSbellard             }
2061b6b029eSbellard             break;
207b689bc57Sbellard         case EXCP0E_PAGE:
208b689bc57Sbellard             info.si_signo = SIGSEGV;
209b689bc57Sbellard             info.si_errno = 0;
210b689bc57Sbellard             if (!(env->error_code & 1))
211b689bc57Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
212b689bc57Sbellard             else
213b689bc57Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
214970a87a6Sbellard             info._sifields._sigfault._addr = env->cr[2];
215b689bc57Sbellard             queue_signal(info.si_signo, &info);
216b689bc57Sbellard             break;
2179de5e440Sbellard         case EXCP00_DIVZ:
218bc8a22ccSbellard             if (env->eflags & VM_MASK) {
219447db213Sbellard                 handle_vm86_trap(env, trapnr);
220bc8a22ccSbellard             } else {
2219de5e440Sbellard                 /* division by zero */
2229de5e440Sbellard                 info.si_signo = SIGFPE;
2239de5e440Sbellard                 info.si_errno = 0;
2249de5e440Sbellard                 info.si_code = TARGET_FPE_INTDIV;
2259de5e440Sbellard                 info._sifields._sigfault._addr = env->eip;
2269de5e440Sbellard                 queue_signal(info.si_signo, &info);
227bc8a22ccSbellard             }
2289de5e440Sbellard             break;
229447db213Sbellard         case EXCP01_SSTP:
230447db213Sbellard         case EXCP03_INT3:
231447db213Sbellard             if (env->eflags & VM_MASK) {
232447db213Sbellard                 handle_vm86_trap(env, trapnr);
233447db213Sbellard             } else {
234447db213Sbellard                 info.si_signo = SIGTRAP;
235447db213Sbellard                 info.si_errno = 0;
236447db213Sbellard                 if (trapnr == EXCP01_SSTP) {
237447db213Sbellard                     info.si_code = TARGET_TRAP_BRKPT;
238447db213Sbellard                     info._sifields._sigfault._addr = env->eip;
239447db213Sbellard                 } else {
240447db213Sbellard                     info.si_code = TARGET_SI_KERNEL;
241447db213Sbellard                     info._sifields._sigfault._addr = 0;
242447db213Sbellard                 }
243447db213Sbellard                 queue_signal(info.si_signo, &info);
244447db213Sbellard             }
245447db213Sbellard             break;
2469de5e440Sbellard         case EXCP04_INTO:
2479de5e440Sbellard         case EXCP05_BOUND:
248bc8a22ccSbellard             if (env->eflags & VM_MASK) {
249447db213Sbellard                 handle_vm86_trap(env, trapnr);
250bc8a22ccSbellard             } else {
2519de5e440Sbellard                 info.si_signo = SIGSEGV;
2529de5e440Sbellard                 info.si_errno = 0;
253b689bc57Sbellard                 info.si_code = TARGET_SI_KERNEL;
2549de5e440Sbellard                 info._sifields._sigfault._addr = 0;
2559de5e440Sbellard                 queue_signal(info.si_signo, &info);
256bc8a22ccSbellard             }
2579de5e440Sbellard             break;
2589de5e440Sbellard         case EXCP06_ILLOP:
2599de5e440Sbellard             info.si_signo = SIGILL;
2609de5e440Sbellard             info.si_errno = 0;
2619de5e440Sbellard             info.si_code = TARGET_ILL_ILLOPN;
2629de5e440Sbellard             info._sifields._sigfault._addr = env->eip;
2639de5e440Sbellard             queue_signal(info.si_signo, &info);
2649de5e440Sbellard             break;
2659de5e440Sbellard         case EXCP_INTERRUPT:
2669de5e440Sbellard             /* just indicate that signals should be handled asap */
2679de5e440Sbellard             break;
2681fddef4bSbellard         case EXCP_DEBUG:
2691fddef4bSbellard             {
2701fddef4bSbellard                 int sig;
2711fddef4bSbellard 
2721fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
2731fddef4bSbellard                 if (sig)
2741fddef4bSbellard                   {
2751fddef4bSbellard                     info.si_signo = sig;
2761fddef4bSbellard                     info.si_errno = 0;
2771fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
2781fddef4bSbellard                     queue_signal(info.si_signo, &info);
2791fddef4bSbellard                   }
2801fddef4bSbellard             }
2811fddef4bSbellard             break;
2821b6b029eSbellard         default:
283970a87a6Sbellard             pc = env->segs[R_CS].base + env->eip;
284bc8a22ccSbellard             fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
285bc8a22ccSbellard                     (long)pc, trapnr);
2861b6b029eSbellard             abort();
2871b6b029eSbellard         }
28866fb9763Sbellard         process_pending_signals(env);
2891b6b029eSbellard     }
2901b6b029eSbellard }
291b346ff46Sbellard #endif
292b346ff46Sbellard 
293b346ff46Sbellard #ifdef TARGET_ARM
294b346ff46Sbellard 
2956f1f31c0Sbellard /* XXX: find a better solution */
2966f1f31c0Sbellard extern void tb_invalidate_page_range(target_ulong start, target_ulong end);
2976f1f31c0Sbellard 
2986f1f31c0Sbellard static void arm_cache_flush(target_ulong start, target_ulong last)
2996f1f31c0Sbellard {
3006f1f31c0Sbellard     target_ulong addr, last1;
3016f1f31c0Sbellard 
3026f1f31c0Sbellard     if (last < start)
3036f1f31c0Sbellard         return;
3046f1f31c0Sbellard     addr = start;
3056f1f31c0Sbellard     for(;;) {
3066f1f31c0Sbellard         last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1;
3076f1f31c0Sbellard         if (last1 > last)
3086f1f31c0Sbellard             last1 = last;
3096f1f31c0Sbellard         tb_invalidate_page_range(addr, last1 + 1);
3106f1f31c0Sbellard         if (last1 == last)
3116f1f31c0Sbellard             break;
3126f1f31c0Sbellard         addr = last1 + 1;
3136f1f31c0Sbellard     }
3146f1f31c0Sbellard }
3156f1f31c0Sbellard 
316b346ff46Sbellard void cpu_loop(CPUARMState *env)
317b346ff46Sbellard {
318b346ff46Sbellard     int trapnr;
319b346ff46Sbellard     unsigned int n, insn;
320b346ff46Sbellard     target_siginfo_t info;
321b5ff1b31Sbellard     uint32_t addr;
322b346ff46Sbellard 
323b346ff46Sbellard     for(;;) {
324b346ff46Sbellard         trapnr = cpu_arm_exec(env);
325b346ff46Sbellard         switch(trapnr) {
326b346ff46Sbellard         case EXCP_UDEF:
327c6981055Sbellard             {
328c6981055Sbellard                 TaskState *ts = env->opaque;
329c6981055Sbellard                 uint32_t opcode;
330c6981055Sbellard 
331c6981055Sbellard                 /* we handle the FPU emulation here, as Linux */
332c6981055Sbellard                 /* we get the opcode */
33353a5960aSpbrook                 opcode = tget32(env->regs[15]);
334c6981055Sbellard 
33519b045deSpbrook                 if (EmulateAll(opcode, &ts->fpa, env) == 0) {
336b346ff46Sbellard                     info.si_signo = SIGILL;
337b346ff46Sbellard                     info.si_errno = 0;
338b346ff46Sbellard                     info.si_code = TARGET_ILL_ILLOPN;
339b346ff46Sbellard                     info._sifields._sigfault._addr = env->regs[15];
340b346ff46Sbellard                     queue_signal(info.si_signo, &info);
341c6981055Sbellard                 } else {
342c6981055Sbellard                     /* increment PC */
343c6981055Sbellard                     env->regs[15] += 4;
344c6981055Sbellard                 }
345c6981055Sbellard             }
346b346ff46Sbellard             break;
347b346ff46Sbellard         case EXCP_SWI:
34806c949e6Spbrook         case EXCP_BKPT:
349b346ff46Sbellard             {
350ce4defa0Spbrook                 env->eabi = 1;
351b346ff46Sbellard                 /* system call */
35206c949e6Spbrook                 if (trapnr == EXCP_BKPT) {
35306c949e6Spbrook                     if (env->thumb) {
35453a5960aSpbrook                         insn = tget16(env->regs[15]);
35506c949e6Spbrook                         n = insn & 0xff;
35606c949e6Spbrook                         env->regs[15] += 2;
35706c949e6Spbrook                     } else {
35853a5960aSpbrook                         insn = tget32(env->regs[15]);
35906c949e6Spbrook                         n = (insn & 0xf) | ((insn >> 4) & 0xff0);
36006c949e6Spbrook                         env->regs[15] += 4;
36106c949e6Spbrook                     }
36206c949e6Spbrook                 } else {
363192c7bd9Sbellard                     if (env->thumb) {
36453a5960aSpbrook                         insn = tget16(env->regs[15] - 2);
365192c7bd9Sbellard                         n = insn & 0xff;
366192c7bd9Sbellard                     } else {
36753a5960aSpbrook                         insn = tget32(env->regs[15] - 4);
368b346ff46Sbellard                         n = insn & 0xffffff;
369192c7bd9Sbellard                     }
37006c949e6Spbrook                 }
371192c7bd9Sbellard 
3726f1f31c0Sbellard                 if (n == ARM_NR_cacheflush) {
3736f1f31c0Sbellard                     arm_cache_flush(env->regs[0], env->regs[1]);
374a4f81979Sbellard                 } else if (n == ARM_NR_semihosting
375a4f81979Sbellard                            || n == ARM_NR_thumb_semihosting) {
376a4f81979Sbellard                     env->regs[0] = do_arm_semihosting (env);
377ce4defa0Spbrook                 } else if (n == 0 || n >= ARM_SYSCALL_BASE
378192c7bd9Sbellard                            || (env->thumb && n == ARM_THUMB_SYSCALL)) {
379b346ff46Sbellard                     /* linux syscall */
380ce4defa0Spbrook                     if (env->thumb || n == 0) {
381192c7bd9Sbellard                         n = env->regs[7];
382192c7bd9Sbellard                     } else {
383b346ff46Sbellard                         n -= ARM_SYSCALL_BASE;
384ce4defa0Spbrook                         env->eabi = 0;
385192c7bd9Sbellard                     }
386b346ff46Sbellard                     env->regs[0] = do_syscall(env,
387b346ff46Sbellard                                               n,
388b346ff46Sbellard                                               env->regs[0],
389b346ff46Sbellard                                               env->regs[1],
390b346ff46Sbellard                                               env->regs[2],
391b346ff46Sbellard                                               env->regs[3],
392b346ff46Sbellard                                               env->regs[4],
393e1a2849cSbellard                                               env->regs[5]);
394b346ff46Sbellard                 } else {
395b346ff46Sbellard                     goto error;
396b346ff46Sbellard                 }
397b346ff46Sbellard             }
398b346ff46Sbellard             break;
39943fff238Sbellard         case EXCP_INTERRUPT:
40043fff238Sbellard             /* just indicate that signals should be handled asap */
40143fff238Sbellard             break;
40268016c62Sbellard         case EXCP_PREFETCH_ABORT:
403b5ff1b31Sbellard             addr = env->cp15.c6_data;
404b5ff1b31Sbellard             goto do_segv;
40568016c62Sbellard         case EXCP_DATA_ABORT:
406b5ff1b31Sbellard             addr = env->cp15.c6_insn;
407b5ff1b31Sbellard             goto do_segv;
408b5ff1b31Sbellard         do_segv:
40968016c62Sbellard             {
41068016c62Sbellard                 info.si_signo = SIGSEGV;
41168016c62Sbellard                 info.si_errno = 0;
41268016c62Sbellard                 /* XXX: check env->error_code */
41368016c62Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
414b5ff1b31Sbellard                 info._sifields._sigfault._addr = addr;
41568016c62Sbellard                 queue_signal(info.si_signo, &info);
41668016c62Sbellard             }
41768016c62Sbellard             break;
4181fddef4bSbellard         case EXCP_DEBUG:
4191fddef4bSbellard             {
4201fddef4bSbellard                 int sig;
4211fddef4bSbellard 
4221fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
4231fddef4bSbellard                 if (sig)
4241fddef4bSbellard                   {
4251fddef4bSbellard                     info.si_signo = sig;
4261fddef4bSbellard                     info.si_errno = 0;
4271fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
4281fddef4bSbellard                     queue_signal(info.si_signo, &info);
4291fddef4bSbellard                   }
4301fddef4bSbellard             }
4311fddef4bSbellard             break;
432b346ff46Sbellard         default:
433b346ff46Sbellard         error:
434b346ff46Sbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
435b346ff46Sbellard                     trapnr);
4367fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
437b346ff46Sbellard             abort();
438b346ff46Sbellard         }
439b346ff46Sbellard         process_pending_signals(env);
440b346ff46Sbellard     }
441b346ff46Sbellard }
442b346ff46Sbellard 
443b346ff46Sbellard #endif
4441b6b029eSbellard 
44593ac68bcSbellard #ifdef TARGET_SPARC
44693ac68bcSbellard 
447060366c5Sbellard //#define DEBUG_WIN
448060366c5Sbellard 
4492623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info
4502623cbafSbellard    can be found at http://www.sics.se/~psm/sparcstack.html */
451060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
452060366c5Sbellard {
453060366c5Sbellard     index = (index + cwp * 16) & (16 * NWINDOWS - 1);
454060366c5Sbellard     /* wrap handling : if cwp is on the last window, then we use the
455060366c5Sbellard        registers 'after' the end */
456060366c5Sbellard     if (index < 8 && env->cwp == (NWINDOWS - 1))
457060366c5Sbellard         index += (16 * NWINDOWS);
458060366c5Sbellard     return index;
459060366c5Sbellard }
460060366c5Sbellard 
4612623cbafSbellard /* save the register window 'cwp1' */
4622623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1)
463060366c5Sbellard {
4642623cbafSbellard     unsigned int i;
46553a5960aSpbrook     target_ulong sp_ptr;
466060366c5Sbellard 
46753a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
468060366c5Sbellard #if defined(DEBUG_WIN)
469060366c5Sbellard     printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
470060366c5Sbellard            (int)sp_ptr, cwp1);
471060366c5Sbellard #endif
4722623cbafSbellard     for(i = 0; i < 16; i++) {
47353a5960aSpbrook         tputl(sp_ptr, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
47453a5960aSpbrook         sp_ptr += sizeof(target_ulong);
4752623cbafSbellard     }
476060366c5Sbellard }
477060366c5Sbellard 
478060366c5Sbellard static void save_window(CPUSPARCState *env)
479060366c5Sbellard {
4805ef54116Sbellard #ifndef TARGET_SPARC64
4812623cbafSbellard     unsigned int new_wim;
4822623cbafSbellard     new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
4832623cbafSbellard         ((1LL << NWINDOWS) - 1);
4842623cbafSbellard     save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
4852623cbafSbellard     env->wim = new_wim;
4865ef54116Sbellard #else
4875ef54116Sbellard     save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
4885ef54116Sbellard     env->cansave++;
4895ef54116Sbellard     env->canrestore--;
4905ef54116Sbellard #endif
491060366c5Sbellard }
492060366c5Sbellard 
493060366c5Sbellard static void restore_window(CPUSPARCState *env)
494060366c5Sbellard {
495060366c5Sbellard     unsigned int new_wim, i, cwp1;
49653a5960aSpbrook     target_ulong sp_ptr;
497060366c5Sbellard 
498060366c5Sbellard     new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
499060366c5Sbellard         ((1LL << NWINDOWS) - 1);
500060366c5Sbellard 
501060366c5Sbellard     /* restore the invalid window */
502060366c5Sbellard     cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
50353a5960aSpbrook     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
504060366c5Sbellard #if defined(DEBUG_WIN)
505060366c5Sbellard     printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
506060366c5Sbellard            (int)sp_ptr, cwp1);
507060366c5Sbellard #endif
5082623cbafSbellard     for(i = 0; i < 16; i++) {
50953a5960aSpbrook         env->regbase[get_reg_index(env, cwp1, 8 + i)] = tgetl(sp_ptr);
51053a5960aSpbrook         sp_ptr += sizeof(target_ulong);
5112623cbafSbellard     }
512060366c5Sbellard     env->wim = new_wim;
5135ef54116Sbellard #ifdef TARGET_SPARC64
5145ef54116Sbellard     env->canrestore++;
5155ef54116Sbellard     if (env->cleanwin < NWINDOWS - 1)
5165ef54116Sbellard 	env->cleanwin++;
5175ef54116Sbellard     env->cansave--;
5185ef54116Sbellard #endif
519060366c5Sbellard }
520060366c5Sbellard 
521060366c5Sbellard static void flush_windows(CPUSPARCState *env)
522060366c5Sbellard {
523060366c5Sbellard     int offset, cwp1;
5242623cbafSbellard 
5252623cbafSbellard     offset = 1;
526060366c5Sbellard     for(;;) {
527060366c5Sbellard         /* if restore would invoke restore_window(), then we can stop */
5282623cbafSbellard         cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
529060366c5Sbellard         if (env->wim & (1 << cwp1))
530060366c5Sbellard             break;
5312623cbafSbellard         save_window_offset(env, cwp1);
532060366c5Sbellard         offset++;
533060366c5Sbellard     }
5342623cbafSbellard     /* set wim so that restore will reload the registers */
5352623cbafSbellard     cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
5362623cbafSbellard     env->wim = 1 << cwp1;
5372623cbafSbellard #if defined(DEBUG_WIN)
5382623cbafSbellard     printf("flush_windows: nb=%d\n", offset - 1);
53980a9d035Sbellard #endif
5402623cbafSbellard }
541060366c5Sbellard 
54293ac68bcSbellard void cpu_loop (CPUSPARCState *env)
54393ac68bcSbellard {
544060366c5Sbellard     int trapnr, ret;
54561ff6f58Sbellard     target_siginfo_t info;
54693ac68bcSbellard 
54793ac68bcSbellard     while (1) {
54893ac68bcSbellard         trapnr = cpu_sparc_exec (env);
54993ac68bcSbellard 
55093ac68bcSbellard         switch (trapnr) {
5515ef54116Sbellard #ifndef TARGET_SPARC64
552060366c5Sbellard         case 0x88:
553060366c5Sbellard         case 0x90:
5545ef54116Sbellard #else
5555ef54116Sbellard         case 0x16d:
5565ef54116Sbellard #endif
557060366c5Sbellard             ret = do_syscall (env, env->gregs[1],
558060366c5Sbellard                               env->regwptr[0], env->regwptr[1],
559060366c5Sbellard                               env->regwptr[2], env->regwptr[3],
560060366c5Sbellard                               env->regwptr[4], env->regwptr[5]);
561060366c5Sbellard             if ((unsigned int)ret >= (unsigned int)(-515)) {
56227908725Sbellard #ifdef TARGET_SPARC64
56327908725Sbellard                 env->xcc |= PSR_CARRY;
56427908725Sbellard #else
56593ac68bcSbellard                 env->psr |= PSR_CARRY;
56627908725Sbellard #endif
567060366c5Sbellard                 ret = -ret;
568060366c5Sbellard             } else {
56927908725Sbellard #ifdef TARGET_SPARC64
57027908725Sbellard                 env->xcc &= ~PSR_CARRY;
57127908725Sbellard #else
572060366c5Sbellard                 env->psr &= ~PSR_CARRY;
57327908725Sbellard #endif
574060366c5Sbellard             }
575060366c5Sbellard             env->regwptr[0] = ret;
576060366c5Sbellard             /* next instruction */
577060366c5Sbellard             env->pc = env->npc;
578060366c5Sbellard             env->npc = env->npc + 4;
579060366c5Sbellard             break;
580060366c5Sbellard         case 0x83: /* flush windows */
5812623cbafSbellard             flush_windows(env);
582060366c5Sbellard             /* next instruction */
583060366c5Sbellard             env->pc = env->npc;
584060366c5Sbellard             env->npc = env->npc + 4;
585060366c5Sbellard             break;
5863475187dSbellard #ifndef TARGET_SPARC64
587060366c5Sbellard         case TT_WIN_OVF: /* window overflow */
588060366c5Sbellard             save_window(env);
589060366c5Sbellard             break;
590060366c5Sbellard         case TT_WIN_UNF: /* window underflow */
591060366c5Sbellard             restore_window(env);
59293ac68bcSbellard             break;
59361ff6f58Sbellard         case TT_TFAULT:
59461ff6f58Sbellard         case TT_DFAULT:
59561ff6f58Sbellard             {
59661ff6f58Sbellard                 info.si_signo = SIGSEGV;
59761ff6f58Sbellard                 info.si_errno = 0;
59861ff6f58Sbellard                 /* XXX: check env->error_code */
59961ff6f58Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
60061ff6f58Sbellard                 info._sifields._sigfault._addr = env->mmuregs[4];
60161ff6f58Sbellard                 queue_signal(info.si_signo, &info);
60261ff6f58Sbellard             }
60361ff6f58Sbellard             break;
6043475187dSbellard #else
6055ef54116Sbellard         case TT_SPILL: /* window overflow */
6065ef54116Sbellard             save_window(env);
6075ef54116Sbellard             break;
6085ef54116Sbellard         case TT_FILL: /* window underflow */
6095ef54116Sbellard             restore_window(env);
6105ef54116Sbellard             break;
6113475187dSbellard 	    // XXX
6123475187dSbellard #endif
61348dc41ebSbellard         case EXCP_INTERRUPT:
61448dc41ebSbellard             /* just indicate that signals should be handled asap */
615e80cfcfcSbellard             break;
6161fddef4bSbellard         case EXCP_DEBUG:
6171fddef4bSbellard             {
6181fddef4bSbellard                 int sig;
6191fddef4bSbellard 
6201fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
6211fddef4bSbellard                 if (sig)
6221fddef4bSbellard                   {
6231fddef4bSbellard                     info.si_signo = sig;
6241fddef4bSbellard                     info.si_errno = 0;
6251fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
6261fddef4bSbellard                     queue_signal(info.si_signo, &info);
6271fddef4bSbellard                   }
6281fddef4bSbellard             }
6291fddef4bSbellard             break;
63093ac68bcSbellard         default:
631060366c5Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
6327fe48483Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
63393ac68bcSbellard             exit (1);
63493ac68bcSbellard         }
63593ac68bcSbellard         process_pending_signals (env);
63693ac68bcSbellard     }
63793ac68bcSbellard }
63893ac68bcSbellard 
63993ac68bcSbellard #endif
64093ac68bcSbellard 
64167867308Sbellard #ifdef TARGET_PPC
6429fddaa0cSbellard 
6439fddaa0cSbellard static inline uint64_t cpu_ppc_get_tb (CPUState *env)
6449fddaa0cSbellard {
6459fddaa0cSbellard     /* TO FIX */
6469fddaa0cSbellard     return 0;
6479fddaa0cSbellard }
6489fddaa0cSbellard 
6499fddaa0cSbellard uint32_t cpu_ppc_load_tbl (CPUState *env)
6509fddaa0cSbellard {
6519fddaa0cSbellard     return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
6529fddaa0cSbellard }
6539fddaa0cSbellard 
6549fddaa0cSbellard uint32_t cpu_ppc_load_tbu (CPUState *env)
6559fddaa0cSbellard {
6569fddaa0cSbellard     return cpu_ppc_get_tb(env) >> 32;
6579fddaa0cSbellard }
6589fddaa0cSbellard 
6599fddaa0cSbellard static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
6609fddaa0cSbellard {
6619fddaa0cSbellard     /* TO FIX */
6629fddaa0cSbellard }
6639fddaa0cSbellard 
6649fddaa0cSbellard void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
6659fddaa0cSbellard {
6669fddaa0cSbellard     cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
6679fddaa0cSbellard }
6689fddaa0cSbellard 
6699fddaa0cSbellard void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
6709fddaa0cSbellard {
6719fddaa0cSbellard     cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
6729fddaa0cSbellard }
6739fddaa0cSbellard 
67476a66253Sj_mayer void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
67576a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_store_tbu") ));
67676a66253Sj_mayer 
67776a66253Sj_mayer uint32_t cpu_ppc601_load_rtcu (CPUState *env)
67876a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_load_tbu") ));
67976a66253Sj_mayer 
68076a66253Sj_mayer void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
6819fddaa0cSbellard {
68276a66253Sj_mayer     cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
6839fddaa0cSbellard }
6849fddaa0cSbellard 
68576a66253Sj_mayer uint32_t cpu_ppc601_load_rtcl (CPUState *env)
6869fddaa0cSbellard {
68776a66253Sj_mayer     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
6889fddaa0cSbellard }
6899fddaa0cSbellard 
69067867308Sbellard void cpu_loop(CPUPPCState *env)
69167867308Sbellard {
69267867308Sbellard     target_siginfo_t info;
69361190b14Sbellard     int trapnr;
69461190b14Sbellard     uint32_t ret;
69567867308Sbellard 
69667867308Sbellard     for(;;) {
69767867308Sbellard         trapnr = cpu_ppc_exec(env);
69861190b14Sbellard         if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
69961190b14Sbellard             trapnr != EXCP_TRACE) {
70061190b14Sbellard             if (loglevel > 0) {
7017fe48483Sbellard                 cpu_dump_state(env, logfile, fprintf, 0);
70261190b14Sbellard             }
70361190b14Sbellard         }
70467867308Sbellard         switch(trapnr) {
70567867308Sbellard         case EXCP_NONE:
70667867308Sbellard             break;
70761190b14Sbellard         case EXCP_SYSCALL_USER:
70867867308Sbellard             /* system call */
70967867308Sbellard             /* WARNING:
71067867308Sbellard              * PPC ABI uses overflow flag in cr0 to signal an error
71167867308Sbellard              * in syscalls.
71267867308Sbellard              */
71361190b14Sbellard #if 0
71461190b14Sbellard             printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
71561190b14Sbellard                    env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
71661190b14Sbellard #endif
71767867308Sbellard             env->crf[0] &= ~0x1;
71867867308Sbellard             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
71967867308Sbellard                              env->gpr[5], env->gpr[6], env->gpr[7],
72067867308Sbellard                              env->gpr[8]);
72167867308Sbellard             if (ret > (uint32_t)(-515)) {
72267867308Sbellard                 env->crf[0] |= 0x1;
72367867308Sbellard                 ret = -ret;
72467867308Sbellard             }
72567867308Sbellard             env->gpr[3] = ret;
72661190b14Sbellard #if 0
72761190b14Sbellard             printf("syscall returned 0x%08x (%d)\n", ret, ret);
72861190b14Sbellard #endif
72961190b14Sbellard             break;
73061190b14Sbellard         case EXCP_RESET:
73161190b14Sbellard             /* Should not happen ! */
73261190b14Sbellard             fprintf(stderr, "RESET asked... Stop emulation\n");
73361190b14Sbellard             if (loglevel)
73461190b14Sbellard                 fprintf(logfile, "RESET asked... Stop emulation\n");
73561190b14Sbellard             abort();
73661190b14Sbellard         case EXCP_MACHINE_CHECK:
73761190b14Sbellard             fprintf(stderr, "Machine check exeption...  Stop emulation\n");
73861190b14Sbellard             if (loglevel)
73961190b14Sbellard                 fprintf(logfile, "RESET asked... Stop emulation\n");
74061190b14Sbellard             info.si_signo = TARGET_SIGBUS;
74161190b14Sbellard             info.si_errno = 0;
74261190b14Sbellard             info.si_code = TARGET_BUS_OBJERR;
74361190b14Sbellard             info._sifields._sigfault._addr = env->nip - 4;
74461190b14Sbellard             queue_signal(info.si_signo, &info);
74561190b14Sbellard         case EXCP_DSI:
7463fc6c082Sbellard             fprintf(stderr, "Invalid data memory access: 0x%08x\n",
7473fc6c082Sbellard                     env->spr[SPR_DAR]);
74861190b14Sbellard             if (loglevel) {
74961190b14Sbellard                 fprintf(logfile, "Invalid data memory access: 0x%08x\n",
7503fc6c082Sbellard                         env->spr[SPR_DAR]);
75161190b14Sbellard             }
7522be0071fSbellard             switch (env->error_code & 0xFF000000) {
7532be0071fSbellard             case 0x40000000:
75461190b14Sbellard                 info.si_signo = TARGET_SIGSEGV;
75561190b14Sbellard                 info.si_errno = 0;
75661190b14Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
75761190b14Sbellard                 break;
7582be0071fSbellard             case 0x04000000:
75961190b14Sbellard                 info.si_signo = TARGET_SIGILL;
76061190b14Sbellard                 info.si_errno = 0;
76161190b14Sbellard                 info.si_code = TARGET_ILL_ILLADR;
76261190b14Sbellard                 break;
7632be0071fSbellard             case 0x08000000:
76461190b14Sbellard                 info.si_signo = TARGET_SIGSEGV;
76561190b14Sbellard                 info.si_errno = 0;
76661190b14Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
76761190b14Sbellard                 break;
76861190b14Sbellard             default:
76961190b14Sbellard                 /* Let's send a regular segfault... */
77061190b14Sbellard                 fprintf(stderr, "Invalid segfault errno (%02x)\n",
77161190b14Sbellard                         env->error_code);
77261190b14Sbellard                 if (loglevel) {
77361190b14Sbellard                     fprintf(logfile, "Invalid segfault errno (%02x)\n",
77461190b14Sbellard                             env->error_code);
77561190b14Sbellard                 }
77661190b14Sbellard                 info.si_signo = TARGET_SIGSEGV;
77761190b14Sbellard                 info.si_errno = 0;
77861190b14Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
77967867308Sbellard                 break;
78067867308Sbellard             }
78161190b14Sbellard             info._sifields._sigfault._addr = env->nip;
78261190b14Sbellard             queue_signal(info.si_signo, &info);
78361190b14Sbellard             break;
78461190b14Sbellard         case EXCP_ISI:
78561190b14Sbellard             fprintf(stderr, "Invalid instruction fetch\n");
78661190b14Sbellard             if (loglevel)
78761190b14Sbellard                 fprintf(logfile, "Invalid instruction fetch\n");
7882be0071fSbellard             switch (env->error_code & 0xFF000000) {
7892be0071fSbellard             case 0x40000000:
79061190b14Sbellard                 info.si_signo = TARGET_SIGSEGV;
79161190b14Sbellard             info.si_errno = 0;
79261190b14Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
79361190b14Sbellard                 break;
7942be0071fSbellard             case 0x10000000:
7952be0071fSbellard             case 0x08000000:
79661190b14Sbellard                 info.si_signo = TARGET_SIGSEGV;
79761190b14Sbellard                 info.si_errno = 0;
79861190b14Sbellard                 info.si_code = TARGET_SEGV_ACCERR;
79961190b14Sbellard                 break;
80067867308Sbellard             default:
80161190b14Sbellard                 /* Let's send a regular segfault... */
80261190b14Sbellard                 fprintf(stderr, "Invalid segfault errno (%02x)\n",
80361190b14Sbellard                         env->error_code);
80461190b14Sbellard                 if (loglevel) {
80561190b14Sbellard                     fprintf(logfile, "Invalid segfault errno (%02x)\n",
80661190b14Sbellard                             env->error_code);
80761190b14Sbellard                 }
80861190b14Sbellard                 info.si_signo = TARGET_SIGSEGV;
80961190b14Sbellard                 info.si_errno = 0;
81061190b14Sbellard                 info.si_code = TARGET_SEGV_MAPERR;
81161190b14Sbellard                 break;
81261190b14Sbellard             }
81361190b14Sbellard             info._sifields._sigfault._addr = env->nip - 4;
81461190b14Sbellard             queue_signal(info.si_signo, &info);
81561190b14Sbellard             break;
81661190b14Sbellard         case EXCP_EXTERNAL:
81761190b14Sbellard             /* Should not happen ! */
81861190b14Sbellard             fprintf(stderr, "External interruption... Stop emulation\n");
81961190b14Sbellard             if (loglevel)
82061190b14Sbellard                 fprintf(logfile, "External interruption... Stop emulation\n");
82161190b14Sbellard             abort();
82261190b14Sbellard         case EXCP_ALIGN:
82361190b14Sbellard             fprintf(stderr, "Invalid unaligned memory access\n");
82461190b14Sbellard             if (loglevel)
82561190b14Sbellard                 fprintf(logfile, "Invalid unaligned memory access\n");
82661190b14Sbellard             info.si_signo = TARGET_SIGBUS;
82761190b14Sbellard             info.si_errno = 0;
82861190b14Sbellard             info.si_code = TARGET_BUS_ADRALN;
82961190b14Sbellard             info._sifields._sigfault._addr = env->nip - 4;
83061190b14Sbellard             queue_signal(info.si_signo, &info);
83161190b14Sbellard             break;
83261190b14Sbellard         case EXCP_PROGRAM:
83361190b14Sbellard             switch (env->error_code & ~0xF) {
83461190b14Sbellard             case EXCP_FP:
83561190b14Sbellard             fprintf(stderr, "Program exception\n");
83661190b14Sbellard                 if (loglevel)
83761190b14Sbellard                     fprintf(logfile, "Program exception\n");
83861190b14Sbellard                 /* Set FX */
83961190b14Sbellard                 env->fpscr[7] |= 0x8;
84061190b14Sbellard                 /* Finally, update FEX */
84161190b14Sbellard                 if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
84261190b14Sbellard                     ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
84361190b14Sbellard                     env->fpscr[7] |= 0x4;
84461190b14Sbellard                 info.si_signo = TARGET_SIGFPE;
84561190b14Sbellard                 info.si_errno = 0;
84661190b14Sbellard                 switch (env->error_code & 0xF) {
84761190b14Sbellard                 case EXCP_FP_OX:
84861190b14Sbellard                     info.si_code = TARGET_FPE_FLTOVF;
84961190b14Sbellard                     break;
85061190b14Sbellard                 case EXCP_FP_UX:
85161190b14Sbellard                     info.si_code = TARGET_FPE_FLTUND;
85261190b14Sbellard                     break;
85361190b14Sbellard                 case EXCP_FP_ZX:
85461190b14Sbellard                 case EXCP_FP_VXZDZ:
85561190b14Sbellard                     info.si_code = TARGET_FPE_FLTDIV;
85661190b14Sbellard                     break;
85761190b14Sbellard                 case EXCP_FP_XX:
85861190b14Sbellard                     info.si_code = TARGET_FPE_FLTRES;
85961190b14Sbellard                     break;
86061190b14Sbellard                 case EXCP_FP_VXSOFT:
86161190b14Sbellard                     info.si_code = TARGET_FPE_FLTINV;
86261190b14Sbellard                     break;
86361190b14Sbellard                 case EXCP_FP_VXNAN:
86461190b14Sbellard                 case EXCP_FP_VXISI:
86561190b14Sbellard                 case EXCP_FP_VXIDI:
86661190b14Sbellard                 case EXCP_FP_VXIMZ:
86761190b14Sbellard                 case EXCP_FP_VXVC:
86861190b14Sbellard                 case EXCP_FP_VXSQRT:
86961190b14Sbellard                 case EXCP_FP_VXCVI:
87061190b14Sbellard                     info.si_code = TARGET_FPE_FLTSUB;
87161190b14Sbellard                     break;
87261190b14Sbellard                 default:
87361190b14Sbellard                     fprintf(stderr, "Unknown floating point exception "
87461190b14Sbellard                             "(%02x)\n", env->error_code);
87561190b14Sbellard                     if (loglevel) {
87661190b14Sbellard                         fprintf(logfile, "Unknown floating point exception "
87761190b14Sbellard                                 "(%02x)\n", env->error_code & 0xF);
87861190b14Sbellard                     }
87961190b14Sbellard                 }
88061190b14Sbellard             break;
88161190b14Sbellard         case EXCP_INVAL:
88261190b14Sbellard                 fprintf(stderr, "Invalid instruction\n");
88361190b14Sbellard                 if (loglevel)
88461190b14Sbellard                     fprintf(logfile, "Invalid instruction\n");
88561190b14Sbellard                 info.si_signo = TARGET_SIGILL;
88661190b14Sbellard                 info.si_errno = 0;
88761190b14Sbellard                 switch (env->error_code & 0xF) {
88861190b14Sbellard                 case EXCP_INVAL_INVAL:
88961190b14Sbellard                     info.si_code = TARGET_ILL_ILLOPC;
89061190b14Sbellard                     break;
89161190b14Sbellard                 case EXCP_INVAL_LSWX:
89261190b14Sbellard             info.si_code = TARGET_ILL_ILLOPN;
89361190b14Sbellard                     break;
89461190b14Sbellard                 case EXCP_INVAL_SPR:
89561190b14Sbellard                     info.si_code = TARGET_ILL_PRVREG;
89661190b14Sbellard                     break;
89761190b14Sbellard                 case EXCP_INVAL_FP:
89861190b14Sbellard                     info.si_code = TARGET_ILL_COPROC;
89961190b14Sbellard                     break;
90061190b14Sbellard                 default:
90161190b14Sbellard                     fprintf(stderr, "Unknown invalid operation (%02x)\n",
90261190b14Sbellard                             env->error_code & 0xF);
90361190b14Sbellard                     if (loglevel) {
90461190b14Sbellard                         fprintf(logfile, "Unknown invalid operation (%02x)\n",
90561190b14Sbellard                                 env->error_code & 0xF);
90661190b14Sbellard                     }
90761190b14Sbellard                     info.si_code = TARGET_ILL_ILLADR;
90861190b14Sbellard                     break;
90961190b14Sbellard                 }
91061190b14Sbellard                 break;
91161190b14Sbellard             case EXCP_PRIV:
91261190b14Sbellard                 fprintf(stderr, "Privilege violation\n");
91361190b14Sbellard                 if (loglevel)
91461190b14Sbellard                     fprintf(logfile, "Privilege violation\n");
91561190b14Sbellard                 info.si_signo = TARGET_SIGILL;
91661190b14Sbellard                 info.si_errno = 0;
91761190b14Sbellard                 switch (env->error_code & 0xF) {
91861190b14Sbellard                 case EXCP_PRIV_OPC:
91961190b14Sbellard                     info.si_code = TARGET_ILL_PRVOPC;
92061190b14Sbellard                     break;
92161190b14Sbellard                 case EXCP_PRIV_REG:
92261190b14Sbellard                     info.si_code = TARGET_ILL_PRVREG;
92361190b14Sbellard                 break;
92461190b14Sbellard                 default:
92561190b14Sbellard                     fprintf(stderr, "Unknown privilege violation (%02x)\n",
92661190b14Sbellard                             env->error_code & 0xF);
92761190b14Sbellard                     info.si_code = TARGET_ILL_PRVOPC;
92861190b14Sbellard                     break;
92961190b14Sbellard                 }
93061190b14Sbellard                 break;
93161190b14Sbellard             case EXCP_TRAP:
93261190b14Sbellard                 fprintf(stderr, "Tried to call a TRAP\n");
93361190b14Sbellard                 if (loglevel)
93461190b14Sbellard                     fprintf(logfile, "Tried to call a TRAP\n");
93561190b14Sbellard                 abort();
93661190b14Sbellard             default:
93761190b14Sbellard                 /* Should not happen ! */
93861190b14Sbellard                 fprintf(stderr, "Unknown program exception (%02x)\n",
93961190b14Sbellard                         env->error_code);
94061190b14Sbellard                 if (loglevel) {
94161190b14Sbellard                     fprintf(logfile, "Unknwon program exception (%02x)\n",
94261190b14Sbellard                             env->error_code);
94361190b14Sbellard                 }
94467867308Sbellard                 abort();
94567867308Sbellard             }
94661190b14Sbellard             info._sifields._sigfault._addr = env->nip - 4;
94761190b14Sbellard             queue_signal(info.si_signo, &info);
94861190b14Sbellard             break;
94961190b14Sbellard         case EXCP_NO_FP:
95061190b14Sbellard             fprintf(stderr, "No floating point allowed\n");
95161190b14Sbellard             if (loglevel)
95261190b14Sbellard                 fprintf(logfile, "No floating point allowed\n");
95361190b14Sbellard             info.si_signo = TARGET_SIGILL;
95461190b14Sbellard             info.si_errno = 0;
95561190b14Sbellard             info.si_code = TARGET_ILL_COPROC;
95661190b14Sbellard             info._sifields._sigfault._addr = env->nip - 4;
95761190b14Sbellard             queue_signal(info.si_signo, &info);
95861190b14Sbellard             break;
95961190b14Sbellard         case EXCP_DECR:
96061190b14Sbellard             /* Should not happen ! */
96161190b14Sbellard             fprintf(stderr, "Decrementer exception\n");
96261190b14Sbellard             if (loglevel)
96361190b14Sbellard                 fprintf(logfile, "Decrementer exception\n");
96461190b14Sbellard             abort();
96561190b14Sbellard         case EXCP_TRACE:
96661190b14Sbellard             /* Do nothing: we use this to trace execution */
96761190b14Sbellard             break;
96861190b14Sbellard         case EXCP_FP_ASSIST:
96961190b14Sbellard             /* Should not happen ! */
97061190b14Sbellard             fprintf(stderr, "Floating point assist exception\n");
97161190b14Sbellard             if (loglevel)
97261190b14Sbellard                 fprintf(logfile, "Floating point assist exception\n");
97361190b14Sbellard             abort();
97461190b14Sbellard         case EXCP_MTMSR:
97561190b14Sbellard             /* We reloaded the msr, just go on */
9769fddaa0cSbellard             if (msr_pr == 0) {
97761190b14Sbellard                 fprintf(stderr, "Tried to go into supervisor mode !\n");
97861190b14Sbellard                 if (loglevel)
97961190b14Sbellard                     fprintf(logfile, "Tried to go into supervisor mode !\n");
98061190b14Sbellard                 abort();
98161190b14Sbellard         }
98261190b14Sbellard             break;
98361190b14Sbellard         case EXCP_BRANCH:
98461190b14Sbellard             /* We stopped because of a jump... */
98561190b14Sbellard             break;
98661190b14Sbellard         case EXCP_INTERRUPT:
98761190b14Sbellard             /* Don't know why this should ever happen... */
98861190b14Sbellard             break;
989a541f297Sbellard         case EXCP_DEBUG:
9901fddef4bSbellard             {
9911fddef4bSbellard                 int sig;
9921fddef4bSbellard 
9931fddef4bSbellard                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
9941fddef4bSbellard                 if (sig)
9951fddef4bSbellard                   {
9961fddef4bSbellard                     info.si_signo = sig;
9971fddef4bSbellard                     info.si_errno = 0;
9981fddef4bSbellard                     info.si_code = TARGET_TRAP_BRKPT;
9991fddef4bSbellard                     queue_signal(info.si_signo, &info);
10001fddef4bSbellard                   }
10011fddef4bSbellard             }
1002a541f297Sbellard             break;
100361190b14Sbellard         default:
100461190b14Sbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
100561190b14Sbellard                     trapnr);
100661190b14Sbellard             if (loglevel) {
100761190b14Sbellard                 fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
100861190b14Sbellard                         "0x%02x - aborting\n", trapnr, env->error_code);
100961190b14Sbellard             }
101061190b14Sbellard             abort();
101161190b14Sbellard         }
101267867308Sbellard         process_pending_signals(env);
101367867308Sbellard     }
101467867308Sbellard }
101567867308Sbellard #endif
101667867308Sbellard 
1017048f6b4dSbellard #ifdef TARGET_MIPS
1018048f6b4dSbellard 
1019048f6b4dSbellard #define MIPS_SYS(name, args) args,
1020048f6b4dSbellard 
1021048f6b4dSbellard static const uint8_t mips_syscall_args[] = {
1022048f6b4dSbellard 	MIPS_SYS(sys_syscall	, 0)	/* 4000 */
1023048f6b4dSbellard 	MIPS_SYS(sys_exit	, 1)
1024048f6b4dSbellard 	MIPS_SYS(sys_fork	, 0)
1025048f6b4dSbellard 	MIPS_SYS(sys_read	, 3)
1026048f6b4dSbellard 	MIPS_SYS(sys_write	, 3)
1027048f6b4dSbellard 	MIPS_SYS(sys_open	, 3)	/* 4005 */
1028048f6b4dSbellard 	MIPS_SYS(sys_close	, 1)
1029048f6b4dSbellard 	MIPS_SYS(sys_waitpid	, 3)
1030048f6b4dSbellard 	MIPS_SYS(sys_creat	, 2)
1031048f6b4dSbellard 	MIPS_SYS(sys_link	, 2)
1032048f6b4dSbellard 	MIPS_SYS(sys_unlink	, 1)	/* 4010 */
1033048f6b4dSbellard 	MIPS_SYS(sys_execve	, 0)
1034048f6b4dSbellard 	MIPS_SYS(sys_chdir	, 1)
1035048f6b4dSbellard 	MIPS_SYS(sys_time	, 1)
1036048f6b4dSbellard 	MIPS_SYS(sys_mknod	, 3)
1037048f6b4dSbellard 	MIPS_SYS(sys_chmod	, 2)	/* 4015 */
1038048f6b4dSbellard 	MIPS_SYS(sys_lchown	, 3)
1039048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1040048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_stat */
1041048f6b4dSbellard 	MIPS_SYS(sys_lseek	, 3)
1042048f6b4dSbellard 	MIPS_SYS(sys_getpid	, 0)	/* 4020 */
1043048f6b4dSbellard 	MIPS_SYS(sys_mount	, 5)
1044048f6b4dSbellard 	MIPS_SYS(sys_oldumount	, 1)
1045048f6b4dSbellard 	MIPS_SYS(sys_setuid	, 1)
1046048f6b4dSbellard 	MIPS_SYS(sys_getuid	, 0)
1047048f6b4dSbellard 	MIPS_SYS(sys_stime	, 1)	/* 4025 */
1048048f6b4dSbellard 	MIPS_SYS(sys_ptrace	, 4)
1049048f6b4dSbellard 	MIPS_SYS(sys_alarm	, 1)
1050048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_fstat */
1051048f6b4dSbellard 	MIPS_SYS(sys_pause	, 0)
1052048f6b4dSbellard 	MIPS_SYS(sys_utime	, 2)	/* 4030 */
1053048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1054048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1055048f6b4dSbellard 	MIPS_SYS(sys_access	, 2)
1056048f6b4dSbellard 	MIPS_SYS(sys_nice	, 1)
1057048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4035 */
1058048f6b4dSbellard 	MIPS_SYS(sys_sync	, 0)
1059048f6b4dSbellard 	MIPS_SYS(sys_kill	, 2)
1060048f6b4dSbellard 	MIPS_SYS(sys_rename	, 2)
1061048f6b4dSbellard 	MIPS_SYS(sys_mkdir	, 2)
1062048f6b4dSbellard 	MIPS_SYS(sys_rmdir	, 1)	/* 4040 */
1063048f6b4dSbellard 	MIPS_SYS(sys_dup		, 1)
1064048f6b4dSbellard 	MIPS_SYS(sys_pipe	, 0)
1065048f6b4dSbellard 	MIPS_SYS(sys_times	, 1)
1066048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1067048f6b4dSbellard 	MIPS_SYS(sys_brk		, 1)	/* 4045 */
1068048f6b4dSbellard 	MIPS_SYS(sys_setgid	, 1)
1069048f6b4dSbellard 	MIPS_SYS(sys_getgid	, 0)
1070048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was signal(2) */
1071048f6b4dSbellard 	MIPS_SYS(sys_geteuid	, 0)
1072048f6b4dSbellard 	MIPS_SYS(sys_getegid	, 0)	/* 4050 */
1073048f6b4dSbellard 	MIPS_SYS(sys_acct	, 0)
1074048f6b4dSbellard 	MIPS_SYS(sys_umount	, 2)
1075048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1076048f6b4dSbellard 	MIPS_SYS(sys_ioctl	, 3)
1077048f6b4dSbellard 	MIPS_SYS(sys_fcntl	, 3)	/* 4055 */
1078048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 2)
1079048f6b4dSbellard 	MIPS_SYS(sys_setpgid	, 2)
1080048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1081048f6b4dSbellard 	MIPS_SYS(sys_olduname	, 1)
1082048f6b4dSbellard 	MIPS_SYS(sys_umask	, 1)	/* 4060 */
1083048f6b4dSbellard 	MIPS_SYS(sys_chroot	, 1)
1084048f6b4dSbellard 	MIPS_SYS(sys_ustat	, 2)
1085048f6b4dSbellard 	MIPS_SYS(sys_dup2	, 2)
1086048f6b4dSbellard 	MIPS_SYS(sys_getppid	, 0)
1087048f6b4dSbellard 	MIPS_SYS(sys_getpgrp	, 0)	/* 4065 */
1088048f6b4dSbellard 	MIPS_SYS(sys_setsid	, 0)
1089048f6b4dSbellard 	MIPS_SYS(sys_sigaction	, 3)
1090048f6b4dSbellard 	MIPS_SYS(sys_sgetmask	, 0)
1091048f6b4dSbellard 	MIPS_SYS(sys_ssetmask	, 1)
1092048f6b4dSbellard 	MIPS_SYS(sys_setreuid	, 2)	/* 4070 */
1093048f6b4dSbellard 	MIPS_SYS(sys_setregid	, 2)
1094048f6b4dSbellard 	MIPS_SYS(sys_sigsuspend	, 0)
1095048f6b4dSbellard 	MIPS_SYS(sys_sigpending	, 1)
1096048f6b4dSbellard 	MIPS_SYS(sys_sethostname	, 2)
1097048f6b4dSbellard 	MIPS_SYS(sys_setrlimit	, 2)	/* 4075 */
1098048f6b4dSbellard 	MIPS_SYS(sys_getrlimit	, 2)
1099048f6b4dSbellard 	MIPS_SYS(sys_getrusage	, 2)
1100048f6b4dSbellard 	MIPS_SYS(sys_gettimeofday, 2)
1101048f6b4dSbellard 	MIPS_SYS(sys_settimeofday, 2)
1102048f6b4dSbellard 	MIPS_SYS(sys_getgroups	, 2)	/* 4080 */
1103048f6b4dSbellard 	MIPS_SYS(sys_setgroups	, 2)
1104048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* old_select */
1105048f6b4dSbellard 	MIPS_SYS(sys_symlink	, 2)
1106048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_lstat */
1107048f6b4dSbellard 	MIPS_SYS(sys_readlink	, 3)	/* 4085 */
1108048f6b4dSbellard 	MIPS_SYS(sys_uselib	, 1)
1109048f6b4dSbellard 	MIPS_SYS(sys_swapon	, 2)
1110048f6b4dSbellard 	MIPS_SYS(sys_reboot	, 3)
1111048f6b4dSbellard 	MIPS_SYS(old_readdir	, 3)
1112048f6b4dSbellard 	MIPS_SYS(old_mmap	, 6)	/* 4090 */
1113048f6b4dSbellard 	MIPS_SYS(sys_munmap	, 2)
1114048f6b4dSbellard 	MIPS_SYS(sys_truncate	, 2)
1115048f6b4dSbellard 	MIPS_SYS(sys_ftruncate	, 2)
1116048f6b4dSbellard 	MIPS_SYS(sys_fchmod	, 2)
1117048f6b4dSbellard 	MIPS_SYS(sys_fchown	, 3)	/* 4095 */
1118048f6b4dSbellard 	MIPS_SYS(sys_getpriority	, 2)
1119048f6b4dSbellard 	MIPS_SYS(sys_setpriority	, 3)
1120048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1121048f6b4dSbellard 	MIPS_SYS(sys_statfs	, 2)
1122048f6b4dSbellard 	MIPS_SYS(sys_fstatfs	, 2)	/* 4100 */
1123048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was ioperm(2) */
1124048f6b4dSbellard 	MIPS_SYS(sys_socketcall	, 2)
1125048f6b4dSbellard 	MIPS_SYS(sys_syslog	, 3)
1126048f6b4dSbellard 	MIPS_SYS(sys_setitimer	, 3)
1127048f6b4dSbellard 	MIPS_SYS(sys_getitimer	, 2)	/* 4105 */
1128048f6b4dSbellard 	MIPS_SYS(sys_newstat	, 2)
1129048f6b4dSbellard 	MIPS_SYS(sys_newlstat	, 2)
1130048f6b4dSbellard 	MIPS_SYS(sys_newfstat	, 2)
1131048f6b4dSbellard 	MIPS_SYS(sys_uname	, 1)
1132048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4110 was iopl(2) */
1133048f6b4dSbellard 	MIPS_SYS(sys_vhangup	, 0)
1134048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_idle() */
1135048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_vm86 */
1136048f6b4dSbellard 	MIPS_SYS(sys_wait4	, 4)
1137048f6b4dSbellard 	MIPS_SYS(sys_swapoff	, 1)	/* 4115 */
1138048f6b4dSbellard 	MIPS_SYS(sys_sysinfo	, 1)
1139048f6b4dSbellard 	MIPS_SYS(sys_ipc		, 6)
1140048f6b4dSbellard 	MIPS_SYS(sys_fsync	, 1)
1141048f6b4dSbellard 	MIPS_SYS(sys_sigreturn	, 0)
1142048f6b4dSbellard 	MIPS_SYS(sys_clone	, 0)	/* 4120 */
1143048f6b4dSbellard 	MIPS_SYS(sys_setdomainname, 2)
1144048f6b4dSbellard 	MIPS_SYS(sys_newuname	, 1)
1145048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_modify_ldt */
1146048f6b4dSbellard 	MIPS_SYS(sys_adjtimex	, 1)
1147048f6b4dSbellard 	MIPS_SYS(sys_mprotect	, 3)	/* 4125 */
1148048f6b4dSbellard 	MIPS_SYS(sys_sigprocmask	, 3)
1149048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was create_module */
1150048f6b4dSbellard 	MIPS_SYS(sys_init_module	, 5)
1151048f6b4dSbellard 	MIPS_SYS(sys_delete_module, 1)
1152048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4130	was get_kernel_syms */
1153048f6b4dSbellard 	MIPS_SYS(sys_quotactl	, 0)
1154048f6b4dSbellard 	MIPS_SYS(sys_getpgid	, 1)
1155048f6b4dSbellard 	MIPS_SYS(sys_fchdir	, 1)
1156048f6b4dSbellard 	MIPS_SYS(sys_bdflush	, 2)
1157048f6b4dSbellard 	MIPS_SYS(sys_sysfs	, 3)	/* 4135 */
1158048f6b4dSbellard 	MIPS_SYS(sys_personality	, 1)
1159048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* for afs_syscall */
1160048f6b4dSbellard 	MIPS_SYS(sys_setfsuid	, 1)
1161048f6b4dSbellard 	MIPS_SYS(sys_setfsgid	, 1)
1162048f6b4dSbellard 	MIPS_SYS(sys_llseek	, 5)	/* 4140 */
1163048f6b4dSbellard 	MIPS_SYS(sys_getdents	, 3)
1164048f6b4dSbellard 	MIPS_SYS(sys_select	, 5)
1165048f6b4dSbellard 	MIPS_SYS(sys_flock	, 2)
1166048f6b4dSbellard 	MIPS_SYS(sys_msync	, 3)
1167048f6b4dSbellard 	MIPS_SYS(sys_readv	, 3)	/* 4145 */
1168048f6b4dSbellard 	MIPS_SYS(sys_writev	, 3)
1169048f6b4dSbellard 	MIPS_SYS(sys_cacheflush	, 3)
1170048f6b4dSbellard 	MIPS_SYS(sys_cachectl	, 3)
1171048f6b4dSbellard 	MIPS_SYS(sys_sysmips	, 4)
1172048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4150 */
1173048f6b4dSbellard 	MIPS_SYS(sys_getsid	, 1)
1174048f6b4dSbellard 	MIPS_SYS(sys_fdatasync	, 0)
1175048f6b4dSbellard 	MIPS_SYS(sys_sysctl	, 1)
1176048f6b4dSbellard 	MIPS_SYS(sys_mlock	, 2)
1177048f6b4dSbellard 	MIPS_SYS(sys_munlock	, 2)	/* 4155 */
1178048f6b4dSbellard 	MIPS_SYS(sys_mlockall	, 1)
1179048f6b4dSbellard 	MIPS_SYS(sys_munlockall	, 0)
1180048f6b4dSbellard 	MIPS_SYS(sys_sched_setparam, 2)
1181048f6b4dSbellard 	MIPS_SYS(sys_sched_getparam, 2)
1182048f6b4dSbellard 	MIPS_SYS(sys_sched_setscheduler, 3)	/* 4160 */
1183048f6b4dSbellard 	MIPS_SYS(sys_sched_getscheduler, 1)
1184048f6b4dSbellard 	MIPS_SYS(sys_sched_yield	, 0)
1185048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_max, 1)
1186048f6b4dSbellard 	MIPS_SYS(sys_sched_get_priority_min, 1)
1187048f6b4dSbellard 	MIPS_SYS(sys_sched_rr_get_interval, 2)	/* 4165 */
1188048f6b4dSbellard 	MIPS_SYS(sys_nanosleep,	2)
1189048f6b4dSbellard 	MIPS_SYS(sys_mremap	, 4)
1190048f6b4dSbellard 	MIPS_SYS(sys_accept	, 3)
1191048f6b4dSbellard 	MIPS_SYS(sys_bind	, 3)
1192048f6b4dSbellard 	MIPS_SYS(sys_connect	, 3)	/* 4170 */
1193048f6b4dSbellard 	MIPS_SYS(sys_getpeername	, 3)
1194048f6b4dSbellard 	MIPS_SYS(sys_getsockname	, 3)
1195048f6b4dSbellard 	MIPS_SYS(sys_getsockopt	, 5)
1196048f6b4dSbellard 	MIPS_SYS(sys_listen	, 2)
1197048f6b4dSbellard 	MIPS_SYS(sys_recv	, 4)	/* 4175 */
1198048f6b4dSbellard 	MIPS_SYS(sys_recvfrom	, 6)
1199048f6b4dSbellard 	MIPS_SYS(sys_recvmsg	, 3)
1200048f6b4dSbellard 	MIPS_SYS(sys_send	, 4)
1201048f6b4dSbellard 	MIPS_SYS(sys_sendmsg	, 3)
1202048f6b4dSbellard 	MIPS_SYS(sys_sendto	, 6)	/* 4180 */
1203048f6b4dSbellard 	MIPS_SYS(sys_setsockopt	, 5)
1204048f6b4dSbellard 	MIPS_SYS(sys_shutdown	, 2)
1205048f6b4dSbellard 	MIPS_SYS(sys_socket	, 3)
1206048f6b4dSbellard 	MIPS_SYS(sys_socketpair	, 4)
1207048f6b4dSbellard 	MIPS_SYS(sys_setresuid	, 3)	/* 4185 */
1208048f6b4dSbellard 	MIPS_SYS(sys_getresuid	, 3)
1209048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* was sys_query_module */
1210048f6b4dSbellard 	MIPS_SYS(sys_poll	, 3)
1211048f6b4dSbellard 	MIPS_SYS(sys_nfsservctl	, 3)
1212048f6b4dSbellard 	MIPS_SYS(sys_setresgid	, 3)	/* 4190 */
1213048f6b4dSbellard 	MIPS_SYS(sys_getresgid	, 3)
1214048f6b4dSbellard 	MIPS_SYS(sys_prctl	, 5)
1215048f6b4dSbellard 	MIPS_SYS(sys_rt_sigreturn, 0)
1216048f6b4dSbellard 	MIPS_SYS(sys_rt_sigaction, 4)
1217048f6b4dSbellard 	MIPS_SYS(sys_rt_sigprocmask, 4)	/* 4195 */
1218048f6b4dSbellard 	MIPS_SYS(sys_rt_sigpending, 2)
1219048f6b4dSbellard 	MIPS_SYS(sys_rt_sigtimedwait, 4)
1220048f6b4dSbellard 	MIPS_SYS(sys_rt_sigqueueinfo, 3)
1221048f6b4dSbellard 	MIPS_SYS(sys_rt_sigsuspend, 0)
1222048f6b4dSbellard 	MIPS_SYS(sys_pread64	, 6)	/* 4200 */
1223048f6b4dSbellard 	MIPS_SYS(sys_pwrite64	, 6)
1224048f6b4dSbellard 	MIPS_SYS(sys_chown	, 3)
1225048f6b4dSbellard 	MIPS_SYS(sys_getcwd	, 2)
1226048f6b4dSbellard 	MIPS_SYS(sys_capget	, 2)
1227048f6b4dSbellard 	MIPS_SYS(sys_capset	, 2)	/* 4205 */
1228048f6b4dSbellard 	MIPS_SYS(sys_sigaltstack	, 0)
1229048f6b4dSbellard 	MIPS_SYS(sys_sendfile	, 4)
1230048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1231048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1232048f6b4dSbellard 	MIPS_SYS(sys_mmap2	, 6)	/* 4210 */
1233048f6b4dSbellard 	MIPS_SYS(sys_truncate64	, 4)
1234048f6b4dSbellard 	MIPS_SYS(sys_ftruncate64	, 4)
1235048f6b4dSbellard 	MIPS_SYS(sys_stat64	, 2)
1236048f6b4dSbellard 	MIPS_SYS(sys_lstat64	, 2)
1237048f6b4dSbellard 	MIPS_SYS(sys_fstat64	, 2)	/* 4215 */
1238048f6b4dSbellard 	MIPS_SYS(sys_pivot_root	, 2)
1239048f6b4dSbellard 	MIPS_SYS(sys_mincore	, 3)
1240048f6b4dSbellard 	MIPS_SYS(sys_madvise	, 3)
1241048f6b4dSbellard 	MIPS_SYS(sys_getdents64	, 3)
1242048f6b4dSbellard 	MIPS_SYS(sys_fcntl64	, 3)	/* 4220 */
1243048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)
1244048f6b4dSbellard 	MIPS_SYS(sys_gettid	, 0)
1245048f6b4dSbellard 	MIPS_SYS(sys_readahead	, 5)
1246048f6b4dSbellard 	MIPS_SYS(sys_setxattr	, 5)
1247048f6b4dSbellard 	MIPS_SYS(sys_lsetxattr	, 5)	/* 4225 */
1248048f6b4dSbellard 	MIPS_SYS(sys_fsetxattr	, 5)
1249048f6b4dSbellard 	MIPS_SYS(sys_getxattr	, 4)
1250048f6b4dSbellard 	MIPS_SYS(sys_lgetxattr	, 4)
1251048f6b4dSbellard 	MIPS_SYS(sys_fgetxattr	, 4)
1252048f6b4dSbellard 	MIPS_SYS(sys_listxattr	, 3)	/* 4230 */
1253048f6b4dSbellard 	MIPS_SYS(sys_llistxattr	, 3)
1254048f6b4dSbellard 	MIPS_SYS(sys_flistxattr	, 3)
1255048f6b4dSbellard 	MIPS_SYS(sys_removexattr	, 2)
1256048f6b4dSbellard 	MIPS_SYS(sys_lremovexattr, 2)
1257048f6b4dSbellard 	MIPS_SYS(sys_fremovexattr, 2)	/* 4235 */
1258048f6b4dSbellard 	MIPS_SYS(sys_tkill	, 2)
1259048f6b4dSbellard 	MIPS_SYS(sys_sendfile64	, 5)
1260048f6b4dSbellard 	MIPS_SYS(sys_futex	, 2)
1261048f6b4dSbellard 	MIPS_SYS(sys_sched_setaffinity, 3)
1262048f6b4dSbellard 	MIPS_SYS(sys_sched_getaffinity, 3)	/* 4240 */
1263048f6b4dSbellard 	MIPS_SYS(sys_io_setup	, 2)
1264048f6b4dSbellard 	MIPS_SYS(sys_io_destroy	, 1)
1265048f6b4dSbellard 	MIPS_SYS(sys_io_getevents, 5)
1266048f6b4dSbellard 	MIPS_SYS(sys_io_submit	, 3)
1267048f6b4dSbellard 	MIPS_SYS(sys_io_cancel	, 3)	/* 4245 */
1268048f6b4dSbellard 	MIPS_SYS(sys_exit_group	, 1)
1269048f6b4dSbellard 	MIPS_SYS(sys_lookup_dcookie, 3)
1270048f6b4dSbellard 	MIPS_SYS(sys_epoll_create, 1)
1271048f6b4dSbellard 	MIPS_SYS(sys_epoll_ctl	, 4)
1272048f6b4dSbellard 	MIPS_SYS(sys_epoll_wait	, 3)	/* 4250 */
1273048f6b4dSbellard 	MIPS_SYS(sys_remap_file_pages, 5)
1274048f6b4dSbellard 	MIPS_SYS(sys_set_tid_address, 1)
1275048f6b4dSbellard 	MIPS_SYS(sys_restart_syscall, 0)
1276048f6b4dSbellard 	MIPS_SYS(sys_fadvise64_64, 7)
1277048f6b4dSbellard 	MIPS_SYS(sys_statfs64	, 3)	/* 4255 */
1278048f6b4dSbellard 	MIPS_SYS(sys_fstatfs64	, 2)
1279048f6b4dSbellard 	MIPS_SYS(sys_timer_create, 3)
1280048f6b4dSbellard 	MIPS_SYS(sys_timer_settime, 4)
1281048f6b4dSbellard 	MIPS_SYS(sys_timer_gettime, 2)
1282048f6b4dSbellard 	MIPS_SYS(sys_timer_getoverrun, 1)	/* 4260 */
1283048f6b4dSbellard 	MIPS_SYS(sys_timer_delete, 1)
1284048f6b4dSbellard 	MIPS_SYS(sys_clock_settime, 2)
1285048f6b4dSbellard 	MIPS_SYS(sys_clock_gettime, 2)
1286048f6b4dSbellard 	MIPS_SYS(sys_clock_getres, 2)
1287048f6b4dSbellard 	MIPS_SYS(sys_clock_nanosleep, 4)	/* 4265 */
1288048f6b4dSbellard 	MIPS_SYS(sys_tgkill	, 3)
1289048f6b4dSbellard 	MIPS_SYS(sys_utimes	, 2)
1290048f6b4dSbellard 	MIPS_SYS(sys_mbind	, 4)
1291048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_get_mempolicy */
1292048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* 4270 sys_set_mempolicy */
1293048f6b4dSbellard 	MIPS_SYS(sys_mq_open	, 4)
1294048f6b4dSbellard 	MIPS_SYS(sys_mq_unlink	, 1)
1295048f6b4dSbellard 	MIPS_SYS(sys_mq_timedsend, 5)
1296048f6b4dSbellard 	MIPS_SYS(sys_mq_timedreceive, 5)
1297048f6b4dSbellard 	MIPS_SYS(sys_mq_notify	, 2)	/* 4275 */
1298048f6b4dSbellard 	MIPS_SYS(sys_mq_getsetattr, 3)
1299048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* sys_vserver */
1300048f6b4dSbellard 	MIPS_SYS(sys_waitid	, 4)
1301048f6b4dSbellard 	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
1302048f6b4dSbellard 	MIPS_SYS(sys_add_key	, 5)
1303048f6b4dSbellard 	MIPS_SYS(sys_request_key	, 4)
1304048f6b4dSbellard 	MIPS_SYS(sys_keyctl	, 5)
13056f5b89a0Sths 	MIPS_SYS(sys_set_thread_area, 1)
1306048f6b4dSbellard };
1307048f6b4dSbellard 
1308048f6b4dSbellard #undef MIPS_SYS
1309048f6b4dSbellard 
1310048f6b4dSbellard void cpu_loop(CPUMIPSState *env)
1311048f6b4dSbellard {
1312048f6b4dSbellard     target_siginfo_t info;
1313048f6b4dSbellard     int trapnr, ret, nb_args;
1314048f6b4dSbellard     unsigned int syscall_num;
1315048f6b4dSbellard     target_ulong arg5, arg6, sp_reg;
1316048f6b4dSbellard 
1317048f6b4dSbellard     for(;;) {
1318048f6b4dSbellard         trapnr = cpu_mips_exec(env);
1319048f6b4dSbellard         switch(trapnr) {
1320048f6b4dSbellard         case EXCP_SYSCALL:
1321048f6b4dSbellard             {
1322048f6b4dSbellard                 syscall_num = env->gpr[2] - 4000;
1323106ec879Sbellard                 env->PC += 4;
1324048f6b4dSbellard                 if (syscall_num >= sizeof(mips_syscall_args)) {
1325048f6b4dSbellard                     ret = -ENOSYS;
1326048f6b4dSbellard                 } else {
1327048f6b4dSbellard                     nb_args = mips_syscall_args[syscall_num];
1328048f6b4dSbellard                     if (nb_args >= 5) {
1329048f6b4dSbellard                         sp_reg = env->gpr[29];
1330048f6b4dSbellard                         /* these arguments are taken from the stack */
133153a5960aSpbrook                         arg5 = tgetl(sp_reg + 16);
1332048f6b4dSbellard                         if (nb_args >= 6) {
133353a5960aSpbrook                             arg6 = tgetl(sp_reg + 20);
1334048f6b4dSbellard                         } else {
1335048f6b4dSbellard                             arg6 = 0;
1336048f6b4dSbellard                         }
1337048f6b4dSbellard                     } else {
1338048f6b4dSbellard                         arg5 = 0;
1339048f6b4dSbellard                         arg6 = 0;
1340048f6b4dSbellard                     }
1341048f6b4dSbellard                     ret = do_syscall(env,
1342048f6b4dSbellard                                      env->gpr[2],
1343048f6b4dSbellard                                      env->gpr[4],
1344048f6b4dSbellard                                      env->gpr[5],
1345048f6b4dSbellard                                      env->gpr[6],
1346048f6b4dSbellard                                      env->gpr[7],
1347048f6b4dSbellard                                      arg5,
1348048f6b4dSbellard                                      arg6);
1349048f6b4dSbellard                 }
1350048f6b4dSbellard                 if ((unsigned int)ret >= (unsigned int)(-1133)) {
1351048f6b4dSbellard                     env->gpr[7] = 1; /* error flag */
1352048f6b4dSbellard                     ret = -ret;
1353048f6b4dSbellard                     env->gpr[0] = ret;
1354048f6b4dSbellard                     env->gpr[2] = ret;
1355048f6b4dSbellard                 } else {
1356048f6b4dSbellard                     env->gpr[7] = 0; /* error flag */
1357048f6b4dSbellard                     env->gpr[2] = ret;
1358048f6b4dSbellard                 }
1359048f6b4dSbellard             }
1360048f6b4dSbellard             break;
1361ca7c2b1bSths         case EXCP_TLBL:
1362ca7c2b1bSths         case EXCP_TLBS:
13636900e84bSbellard         case EXCP_CpU:
1364048f6b4dSbellard         case EXCP_RI:
1365048f6b4dSbellard             info.si_signo = TARGET_SIGILL;
1366048f6b4dSbellard             info.si_errno = 0;
1367048f6b4dSbellard             info.si_code = 0;
1368048f6b4dSbellard             queue_signal(info.si_signo, &info);
1369048f6b4dSbellard             break;
1370106ec879Sbellard         case EXCP_INTERRUPT:
1371106ec879Sbellard             /* just indicate that signals should be handled asap */
1372106ec879Sbellard             break;
1373d08b2a28Spbrook         case EXCP_DEBUG:
1374d08b2a28Spbrook             {
1375d08b2a28Spbrook                 int sig;
1376d08b2a28Spbrook 
1377d08b2a28Spbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
1378d08b2a28Spbrook                 if (sig)
1379d08b2a28Spbrook                   {
1380d08b2a28Spbrook                     info.si_signo = sig;
1381d08b2a28Spbrook                     info.si_errno = 0;
1382d08b2a28Spbrook                     info.si_code = TARGET_TRAP_BRKPT;
1383d08b2a28Spbrook                     queue_signal(info.si_signo, &info);
1384d08b2a28Spbrook                   }
1385d08b2a28Spbrook             }
1386d08b2a28Spbrook             break;
1387048f6b4dSbellard         default:
1388048f6b4dSbellard             //        error:
1389048f6b4dSbellard             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
1390048f6b4dSbellard                     trapnr);
1391048f6b4dSbellard             cpu_dump_state(env, stderr, fprintf, 0);
1392048f6b4dSbellard             abort();
1393048f6b4dSbellard         }
1394048f6b4dSbellard         process_pending_signals(env);
1395048f6b4dSbellard     }
1396048f6b4dSbellard }
1397048f6b4dSbellard #endif
1398048f6b4dSbellard 
1399fdf9b3e8Sbellard #ifdef TARGET_SH4
1400fdf9b3e8Sbellard void cpu_loop (CPUState *env)
1401fdf9b3e8Sbellard {
1402fdf9b3e8Sbellard     int trapnr, ret;
1403355fb23dSpbrook     target_siginfo_t info;
1404fdf9b3e8Sbellard 
1405fdf9b3e8Sbellard     while (1) {
1406fdf9b3e8Sbellard         trapnr = cpu_sh4_exec (env);
1407fdf9b3e8Sbellard 
1408fdf9b3e8Sbellard         switch (trapnr) {
1409fdf9b3e8Sbellard         case 0x160:
1410fdf9b3e8Sbellard             ret = do_syscall(env,
14119c2a9ea1Spbrook                              env->gregs[3],
14129c2a9ea1Spbrook                              env->gregs[4],
14139c2a9ea1Spbrook                              env->gregs[5],
14149c2a9ea1Spbrook                              env->gregs[6],
14159c2a9ea1Spbrook                              env->gregs[7],
14169c2a9ea1Spbrook                              env->gregs[0],
1417fdf9b3e8Sbellard                              0);
14189c2a9ea1Spbrook             env->gregs[0] = ret;
1419fdf9b3e8Sbellard             env->pc += 2;
1420fdf9b3e8Sbellard             break;
1421355fb23dSpbrook         case EXCP_DEBUG:
1422355fb23dSpbrook             {
1423355fb23dSpbrook                 int sig;
1424355fb23dSpbrook 
1425355fb23dSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
1426355fb23dSpbrook                 if (sig)
1427355fb23dSpbrook                   {
1428355fb23dSpbrook                     info.si_signo = sig;
1429355fb23dSpbrook                     info.si_errno = 0;
1430355fb23dSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
1431355fb23dSpbrook                     queue_signal(info.si_signo, &info);
1432355fb23dSpbrook                   }
1433355fb23dSpbrook             }
1434355fb23dSpbrook             break;
1435fdf9b3e8Sbellard         default:
1436fdf9b3e8Sbellard             printf ("Unhandled trap: 0x%x\n", trapnr);
1437fdf9b3e8Sbellard             cpu_dump_state(env, stderr, fprintf, 0);
1438fdf9b3e8Sbellard             exit (1);
1439fdf9b3e8Sbellard         }
1440fdf9b3e8Sbellard         process_pending_signals (env);
1441fdf9b3e8Sbellard     }
1442fdf9b3e8Sbellard }
1443fdf9b3e8Sbellard #endif
1444fdf9b3e8Sbellard 
1445e6e5906bSpbrook #ifdef TARGET_M68K
1446e6e5906bSpbrook 
1447e6e5906bSpbrook void cpu_loop(CPUM68KState *env)
1448e6e5906bSpbrook {
1449e6e5906bSpbrook     int trapnr;
1450e6e5906bSpbrook     unsigned int n;
1451e6e5906bSpbrook     target_siginfo_t info;
1452e6e5906bSpbrook     TaskState *ts = env->opaque;
1453e6e5906bSpbrook 
1454e6e5906bSpbrook     for(;;) {
1455e6e5906bSpbrook         trapnr = cpu_m68k_exec(env);
1456e6e5906bSpbrook         switch(trapnr) {
1457e6e5906bSpbrook         case EXCP_ILLEGAL:
1458e6e5906bSpbrook             {
1459e6e5906bSpbrook                 if (ts->sim_syscalls) {
1460e6e5906bSpbrook                     uint16_t nr;
1461e6e5906bSpbrook                     nr = lduw(env->pc + 2);
1462e6e5906bSpbrook                     env->pc += 4;
1463e6e5906bSpbrook                     do_m68k_simcall(env, nr);
1464e6e5906bSpbrook                 } else {
1465e6e5906bSpbrook                     goto do_sigill;
1466e6e5906bSpbrook                 }
1467e6e5906bSpbrook             }
1468e6e5906bSpbrook             break;
1469e6e5906bSpbrook         case EXCP_HALTED:
1470e6e5906bSpbrook             /* Semihosing syscall.  */
1471e6e5906bSpbrook             env->pc += 2;
1472e6e5906bSpbrook             do_m68k_semihosting(env, env->dregs[0]);
1473e6e5906bSpbrook             break;
1474e6e5906bSpbrook         case EXCP_LINEA:
1475e6e5906bSpbrook         case EXCP_LINEF:
1476e6e5906bSpbrook         case EXCP_UNSUPPORTED:
1477e6e5906bSpbrook         do_sigill:
1478e6e5906bSpbrook             info.si_signo = SIGILL;
1479e6e5906bSpbrook             info.si_errno = 0;
1480e6e5906bSpbrook             info.si_code = TARGET_ILL_ILLOPN;
1481e6e5906bSpbrook             info._sifields._sigfault._addr = env->pc;
1482e6e5906bSpbrook             queue_signal(info.si_signo, &info);
1483e6e5906bSpbrook             break;
1484e6e5906bSpbrook         case EXCP_TRAP0:
1485e6e5906bSpbrook             {
1486e6e5906bSpbrook                 ts->sim_syscalls = 0;
1487e6e5906bSpbrook                 n = env->dregs[0];
1488e6e5906bSpbrook                 env->pc += 2;
1489e6e5906bSpbrook                 env->dregs[0] = do_syscall(env,
1490e6e5906bSpbrook                                           n,
1491e6e5906bSpbrook                                           env->dregs[1],
1492e6e5906bSpbrook                                           env->dregs[2],
1493e6e5906bSpbrook                                           env->dregs[3],
1494e6e5906bSpbrook                                           env->dregs[4],
1495e6e5906bSpbrook                                           env->dregs[5],
1496e6e5906bSpbrook                                           env->dregs[6]);
1497e6e5906bSpbrook             }
1498e6e5906bSpbrook             break;
1499e6e5906bSpbrook         case EXCP_INTERRUPT:
1500e6e5906bSpbrook             /* just indicate that signals should be handled asap */
1501e6e5906bSpbrook             break;
1502e6e5906bSpbrook         case EXCP_ACCESS:
1503e6e5906bSpbrook             {
1504e6e5906bSpbrook                 info.si_signo = SIGSEGV;
1505e6e5906bSpbrook                 info.si_errno = 0;
1506e6e5906bSpbrook                 /* XXX: check env->error_code */
1507e6e5906bSpbrook                 info.si_code = TARGET_SEGV_MAPERR;
1508e6e5906bSpbrook                 info._sifields._sigfault._addr = env->mmu.ar;
1509e6e5906bSpbrook                 queue_signal(info.si_signo, &info);
1510e6e5906bSpbrook             }
1511e6e5906bSpbrook             break;
1512e6e5906bSpbrook         case EXCP_DEBUG:
1513e6e5906bSpbrook             {
1514e6e5906bSpbrook                 int sig;
1515e6e5906bSpbrook 
1516e6e5906bSpbrook                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
1517e6e5906bSpbrook                 if (sig)
1518e6e5906bSpbrook                   {
1519e6e5906bSpbrook                     info.si_signo = sig;
1520e6e5906bSpbrook                     info.si_errno = 0;
1521e6e5906bSpbrook                     info.si_code = TARGET_TRAP_BRKPT;
1522e6e5906bSpbrook                     queue_signal(info.si_signo, &info);
1523e6e5906bSpbrook                   }
1524e6e5906bSpbrook             }
1525e6e5906bSpbrook             break;
1526e6e5906bSpbrook         default:
1527e6e5906bSpbrook             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
1528e6e5906bSpbrook                     trapnr);
1529e6e5906bSpbrook             cpu_dump_state(env, stderr, fprintf, 0);
1530e6e5906bSpbrook             abort();
1531e6e5906bSpbrook         }
1532e6e5906bSpbrook         process_pending_signals(env);
1533e6e5906bSpbrook     }
1534e6e5906bSpbrook }
1535e6e5906bSpbrook #endif /* TARGET_M68K */
1536e6e5906bSpbrook 
153731e31b8aSbellard void usage(void)
153831e31b8aSbellard {
153984f2e8efSbellard     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
1540*b1f9be31Sj_mayer            "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n"
1541b346ff46Sbellard            "Linux CPU emulator (compiled for %s emulation)\n"
1542d691f669Sbellard            "\n"
1543d691f669Sbellard            "-h           print this help\n"
154474c33bedSbellard            "-g port      wait gdb connection to port\n"
1545b346ff46Sbellard            "-L path      set the elf interpreter prefix (default=%s)\n"
1546b346ff46Sbellard            "-s size      set the stack size in bytes (default=%ld)\n"
1547*b1f9be31Sj_mayer            "-cpu model   select CPU (-cpu ? for list)\n"
154854936004Sbellard            "\n"
154954936004Sbellard            "debug options:\n"
1550c6981055Sbellard #ifdef USE_CODE_COPY
1551c6981055Sbellard            "-no-code-copy   disable code copy acceleration\n"
1552c6981055Sbellard #endif
15536f1f31c0Sbellard            "-d options   activate log (logfile=%s)\n"
155454936004Sbellard            "-p pagesize  set the host page size to 'pagesize'\n",
1555b346ff46Sbellard            TARGET_ARCH,
1556d691f669Sbellard            interp_prefix,
155754936004Sbellard            x86_stack_size,
155854936004Sbellard            DEBUG_LOGFILE);
155974cd30b8Sbellard     _exit(1);
156031e31b8aSbellard }
156131e31b8aSbellard 
15629de5e440Sbellard /* XXX: currently only used for async signals (see signal.c) */
1563b346ff46Sbellard CPUState *global_env;
156459faf6d6Sbellard 
1565851e67a1Sbellard /* used to free thread contexts */
1566851e67a1Sbellard TaskState *first_task_state;
15679de5e440Sbellard 
156831e31b8aSbellard int main(int argc, char **argv)
156931e31b8aSbellard {
157031e31b8aSbellard     const char *filename;
1571*b1f9be31Sj_mayer     const char *cpu_model;
157201ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
157331e31b8aSbellard     struct image_info info1, *info = &info1;
1574851e67a1Sbellard     TaskState ts1, *ts = &ts1;
1575b346ff46Sbellard     CPUState *env;
1576586314f2Sbellard     int optind;
1577d691f669Sbellard     const char *r;
157874c33bedSbellard     int gdbstub_port = 0;
157931e31b8aSbellard 
158031e31b8aSbellard     if (argc <= 1)
158131e31b8aSbellard         usage();
1582f801f97eSbellard 
1583cc38b844Sbellard     /* init debug */
1584cc38b844Sbellard     cpu_set_log_filename(DEBUG_LOGFILE);
1585cc38b844Sbellard 
1586*b1f9be31Sj_mayer     cpu_model = NULL;
1587586314f2Sbellard     optind = 1;
1588d691f669Sbellard     for(;;) {
1589d691f669Sbellard         if (optind >= argc)
1590d691f669Sbellard             break;
1591d691f669Sbellard         r = argv[optind];
1592d691f669Sbellard         if (r[0] != '-')
1593d691f669Sbellard             break;
1594586314f2Sbellard         optind++;
1595d691f669Sbellard         r++;
1596d691f669Sbellard         if (!strcmp(r, "-")) {
1597d691f669Sbellard             break;
1598d691f669Sbellard         } else if (!strcmp(r, "d")) {
1599e19e89a5Sbellard             int mask;
1600e19e89a5Sbellard             CPULogItem *item;
1601e19e89a5Sbellard 
16026f1f31c0Sbellard 	    if (optind >= argc)
16036f1f31c0Sbellard 		break;
16046f1f31c0Sbellard 
16056f1f31c0Sbellard 	    r = argv[optind++];
16066f1f31c0Sbellard             mask = cpu_str_to_log_mask(r);
1607e19e89a5Sbellard             if (!mask) {
1608e19e89a5Sbellard                 printf("Log items (comma separated):\n");
1609e19e89a5Sbellard                 for(item = cpu_log_items; item->mask != 0; item++) {
1610e19e89a5Sbellard                     printf("%-10s %s\n", item->name, item->help);
1611e19e89a5Sbellard                 }
1612e19e89a5Sbellard                 exit(1);
1613e19e89a5Sbellard             }
1614e19e89a5Sbellard             cpu_set_log(mask);
1615d691f669Sbellard         } else if (!strcmp(r, "s")) {
1616d691f669Sbellard             r = argv[optind++];
1617d691f669Sbellard             x86_stack_size = strtol(r, (char **)&r, 0);
1618d691f669Sbellard             if (x86_stack_size <= 0)
1619d691f669Sbellard                 usage();
1620d691f669Sbellard             if (*r == 'M')
1621d691f669Sbellard                 x86_stack_size *= 1024 * 1024;
1622d691f669Sbellard             else if (*r == 'k' || *r == 'K')
1623d691f669Sbellard                 x86_stack_size *= 1024;
1624d691f669Sbellard         } else if (!strcmp(r, "L")) {
1625d691f669Sbellard             interp_prefix = argv[optind++];
162654936004Sbellard         } else if (!strcmp(r, "p")) {
162783fb7adfSbellard             qemu_host_page_size = atoi(argv[optind++]);
162883fb7adfSbellard             if (qemu_host_page_size == 0 ||
162983fb7adfSbellard                 (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
163054936004Sbellard                 fprintf(stderr, "page size must be a power of two\n");
163154936004Sbellard                 exit(1);
163254936004Sbellard             }
16331fddef4bSbellard         } else if (!strcmp(r, "g")) {
163474c33bedSbellard             gdbstub_port = atoi(argv[optind++]);
1635c5937220Spbrook 	} else if (!strcmp(r, "r")) {
1636c5937220Spbrook 	    qemu_uname_release = argv[optind++];
1637*b1f9be31Sj_mayer         } else if (!strcmp(r, "cpu")) {
1638*b1f9be31Sj_mayer             cpu_model = argv[optind++];
1639*b1f9be31Sj_mayer             if (strcmp(cpu_model, "?") == 0) {
1640*b1f9be31Sj_mayer #if defined(TARGET_PPC)
1641*b1f9be31Sj_mayer                 ppc_cpu_list(stdout, &fprintf);
1642*b1f9be31Sj_mayer #elif defined(TARGET_ARM)
1643*b1f9be31Sj_mayer                 arm_cpu_list();
1644*b1f9be31Sj_mayer #elif defined(TARGET_MIPS)
1645*b1f9be31Sj_mayer                 mips_cpu_list(stdout, &fprintf);
1646*b1f9be31Sj_mayer #endif
1647*b1f9be31Sj_mayer                 exit(1);
1648*b1f9be31Sj_mayer             }
1649c6981055Sbellard         } else
1650c6981055Sbellard #ifdef USE_CODE_COPY
1651c6981055Sbellard         if (!strcmp(r, "no-code-copy")) {
1652c6981055Sbellard             code_copy_enabled = 0;
1653c6981055Sbellard         } else
1654c6981055Sbellard #endif
1655c6981055Sbellard         {
1656d691f669Sbellard             usage();
1657586314f2Sbellard         }
1658d691f669Sbellard     }
1659d691f669Sbellard     if (optind >= argc)
1660d691f669Sbellard         usage();
1661586314f2Sbellard     filename = argv[optind];
166231e31b8aSbellard 
166331e31b8aSbellard     /* Zero out regs */
166401ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
166531e31b8aSbellard 
166631e31b8aSbellard     /* Zero out image_info */
166731e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
166831e31b8aSbellard 
166974cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
167074cd30b8Sbellard     init_paths(interp_prefix);
167174cd30b8Sbellard 
167283fb7adfSbellard     /* NOTE: we need to init the CPU at this stage to get
167383fb7adfSbellard        qemu_host_page_size */
1674b346ff46Sbellard     env = cpu_init();
167515338fd7Sbellard     global_env = env;
167654936004Sbellard 
1677e5fe0c52Spbrook     if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
167831e31b8aSbellard 	printf("Error loading %s\n", filename);
167974cd30b8Sbellard 	_exit(1);
168031e31b8aSbellard     }
168131e31b8aSbellard 
16824b74fe1fSbellard     if (loglevel) {
168354936004Sbellard         page_dump(logfile);
168454936004Sbellard 
16854b74fe1fSbellard         fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
16864b74fe1fSbellard         fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
16874b74fe1fSbellard         fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
1688e5fe0c52Spbrook         fprintf(logfile, "start_data  0x%08lx\n" , info->start_data);
16894b74fe1fSbellard         fprintf(logfile, "end_data    0x%08lx\n" , info->end_data);
16904b74fe1fSbellard         fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
16914b74fe1fSbellard         fprintf(logfile, "brk         0x%08lx\n" , info->brk);
1692b346ff46Sbellard         fprintf(logfile, "entry       0x%08lx\n" , info->entry);
16934b74fe1fSbellard     }
169431e31b8aSbellard 
169553a5960aSpbrook     target_set_brk(info->brk);
169631e31b8aSbellard     syscall_init();
169766fb9763Sbellard     signal_init();
169831e31b8aSbellard 
1699851e67a1Sbellard     /* build Task State */
1700851e67a1Sbellard     memset(ts, 0, sizeof(TaskState));
1701851e67a1Sbellard     env->opaque = ts;
1702851e67a1Sbellard     ts->used = 1;
1703978efd6aSpbrook     ts->info = info;
170459faf6d6Sbellard     env->user_mode_only = 1;
1705851e67a1Sbellard 
1706b346ff46Sbellard #if defined(TARGET_I386)
17072e255c6bSbellard     cpu_x86_set_cpl(env, 3);
17082e255c6bSbellard 
17093802ce26Sbellard     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
17101bde465eSbellard     env->hflags |= HF_PE_MASK;
17111bde465eSbellard     if (env->cpuid_features & CPUID_SSE) {
17121bde465eSbellard         env->cr[4] |= CR4_OSFXSR_MASK;
17131bde465eSbellard         env->hflags |= HF_OSFXSR_MASK;
17141bde465eSbellard     }
17153802ce26Sbellard 
1716415e561fSbellard     /* flags setup : we activate the IRQs by default as in user mode */
1717415e561fSbellard     env->eflags |= IF_MASK;
1718415e561fSbellard 
17196dbad63eSbellard     /* linux register setup */
17200ecfa993Sbellard     env->regs[R_EAX] = regs->eax;
17210ecfa993Sbellard     env->regs[R_EBX] = regs->ebx;
17220ecfa993Sbellard     env->regs[R_ECX] = regs->ecx;
17230ecfa993Sbellard     env->regs[R_EDX] = regs->edx;
17240ecfa993Sbellard     env->regs[R_ESI] = regs->esi;
17250ecfa993Sbellard     env->regs[R_EDI] = regs->edi;
17260ecfa993Sbellard     env->regs[R_EBP] = regs->ebp;
17270ecfa993Sbellard     env->regs[R_ESP] = regs->esp;
1728dab2ed99Sbellard     env->eip = regs->eip;
172931e31b8aSbellard 
1730f4beb510Sbellard     /* linux interrupt setup */
173153a5960aSpbrook     env->idt.base = h2g(idt_table);
1732f4beb510Sbellard     env->idt.limit = sizeof(idt_table) - 1;
1733f4beb510Sbellard     set_idt(0, 0);
1734f4beb510Sbellard     set_idt(1, 0);
1735f4beb510Sbellard     set_idt(2, 0);
1736f4beb510Sbellard     set_idt(3, 3);
1737f4beb510Sbellard     set_idt(4, 3);
1738f4beb510Sbellard     set_idt(5, 3);
1739f4beb510Sbellard     set_idt(6, 0);
1740f4beb510Sbellard     set_idt(7, 0);
1741f4beb510Sbellard     set_idt(8, 0);
1742f4beb510Sbellard     set_idt(9, 0);
1743f4beb510Sbellard     set_idt(10, 0);
1744f4beb510Sbellard     set_idt(11, 0);
1745f4beb510Sbellard     set_idt(12, 0);
1746f4beb510Sbellard     set_idt(13, 0);
1747f4beb510Sbellard     set_idt(14, 0);
1748f4beb510Sbellard     set_idt(15, 0);
1749f4beb510Sbellard     set_idt(16, 0);
1750f4beb510Sbellard     set_idt(17, 0);
1751f4beb510Sbellard     set_idt(18, 0);
1752f4beb510Sbellard     set_idt(19, 0);
1753f4beb510Sbellard     set_idt(0x80, 3);
1754f4beb510Sbellard 
17556dbad63eSbellard     /* linux segment setup */
175653a5960aSpbrook     env->gdt.base = h2g(gdt_table);
17576dbad63eSbellard     env->gdt.limit = sizeof(gdt_table) - 1;
1758f4beb510Sbellard     write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
1759f4beb510Sbellard              DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
1760f4beb510Sbellard              (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
1761f4beb510Sbellard     write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
1762f4beb510Sbellard              DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
1763f4beb510Sbellard              (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
17646dbad63eSbellard     cpu_x86_load_seg(env, R_CS, __USER_CS);
17656dbad63eSbellard     cpu_x86_load_seg(env, R_DS, __USER_DS);
17666dbad63eSbellard     cpu_x86_load_seg(env, R_ES, __USER_DS);
17676dbad63eSbellard     cpu_x86_load_seg(env, R_SS, __USER_DS);
17686dbad63eSbellard     cpu_x86_load_seg(env, R_FS, __USER_DS);
17696dbad63eSbellard     cpu_x86_load_seg(env, R_GS, __USER_DS);
177092ccca6aSbellard 
1771b346ff46Sbellard #elif defined(TARGET_ARM)
1772b346ff46Sbellard     {
1773b346ff46Sbellard         int i;
1774*b1f9be31Sj_mayer         if (cpu_model == NULL)
1775*b1f9be31Sj_mayer             cpu_model = "arm926";
1776*b1f9be31Sj_mayer         cpu_arm_set_model(env, cpu_model);
1777b5ff1b31Sbellard         cpsr_write(env, regs->uregs[16], 0xffffffff);
1778b346ff46Sbellard         for(i = 0; i < 16; i++) {
1779b346ff46Sbellard             env->regs[i] = regs->uregs[i];
1780b346ff46Sbellard         }
1781a4f81979Sbellard         ts->stack_base = info->start_stack;
1782a4f81979Sbellard         ts->heap_base = info->brk;
1783a4f81979Sbellard         /* This will be filled in on the first SYS_HEAPINFO call.  */
1784a4f81979Sbellard         ts->heap_limit = 0;
1785b346ff46Sbellard     }
178693ac68bcSbellard #elif defined(TARGET_SPARC)
1787060366c5Sbellard     {
1788060366c5Sbellard         int i;
1789060366c5Sbellard 	env->pc = regs->pc;
1790060366c5Sbellard 	env->npc = regs->npc;
1791060366c5Sbellard         env->y = regs->y;
1792060366c5Sbellard         for(i = 0; i < 8; i++)
1793060366c5Sbellard             env->gregs[i] = regs->u_regs[i];
1794060366c5Sbellard         for(i = 0; i < 8; i++)
1795060366c5Sbellard             env->regwptr[i] = regs->u_regs[i + 8];
1796060366c5Sbellard     }
179767867308Sbellard #elif defined(TARGET_PPC)
179867867308Sbellard     {
17993fc6c082Sbellard         ppc_def_t *def;
180067867308Sbellard         int i;
18013fc6c082Sbellard 
18023fc6c082Sbellard         /* Choose and initialise CPU */
1803*b1f9be31Sj_mayer         if (cpu_model == NULL)
1804*b1f9be31Sj_mayer             cpu_model = "750";
1805*b1f9be31Sj_mayer         ppc_find_by_name(cpu_model, &def);
18063fc6c082Sbellard         if (def == NULL) {
1807c68ea704Sbellard             cpu_abort(env,
18083fc6c082Sbellard                       "Unable to find PowerPC CPU definition\n");
18093fc6c082Sbellard         }
1810c68ea704Sbellard         cpu_ppc_register(env, def);
18113fc6c082Sbellard 
181261190b14Sbellard         for (i = 0; i < 32; i++) {
18134c2e770fSbellard             if (i != 12 && i != 6 && i != 13)
181467867308Sbellard                 env->msr[i] = (regs->msr >> i) & 1;
181561190b14Sbellard         }
181667867308Sbellard         env->nip = regs->nip;
181767867308Sbellard         for(i = 0; i < 32; i++) {
181867867308Sbellard             env->gpr[i] = regs->gpr[i];
181967867308Sbellard         }
182067867308Sbellard     }
1821e6e5906bSpbrook #elif defined(TARGET_M68K)
1822e6e5906bSpbrook     {
1823e6e5906bSpbrook         m68k_def_t *def;
1824e6e5906bSpbrook         def = m68k_find_by_name("cfv4e");
1825e6e5906bSpbrook         if (def == NULL) {
1826e6e5906bSpbrook             cpu_abort(cpu_single_env,
1827e6e5906bSpbrook                       "Unable to find m68k CPU definition\n");
1828e6e5906bSpbrook         }
1829e6e5906bSpbrook         cpu_m68k_register(cpu_single_env, def);
1830e6e5906bSpbrook         env->pc = regs->pc;
1831e6e5906bSpbrook         env->dregs[0] = regs->d0;
1832e6e5906bSpbrook         env->dregs[1] = regs->d1;
1833e6e5906bSpbrook         env->dregs[2] = regs->d2;
1834e6e5906bSpbrook         env->dregs[3] = regs->d3;
1835e6e5906bSpbrook         env->dregs[4] = regs->d4;
1836e6e5906bSpbrook         env->dregs[5] = regs->d5;
1837e6e5906bSpbrook         env->dregs[6] = regs->d6;
1838e6e5906bSpbrook         env->dregs[7] = regs->d7;
1839e6e5906bSpbrook         env->aregs[0] = regs->a0;
1840e6e5906bSpbrook         env->aregs[1] = regs->a1;
1841e6e5906bSpbrook         env->aregs[2] = regs->a2;
1842e6e5906bSpbrook         env->aregs[3] = regs->a3;
1843e6e5906bSpbrook         env->aregs[4] = regs->a4;
1844e6e5906bSpbrook         env->aregs[5] = regs->a5;
1845e6e5906bSpbrook         env->aregs[6] = regs->a6;
1846e6e5906bSpbrook         env->aregs[7] = regs->usp;
1847e6e5906bSpbrook         env->sr = regs->sr;
1848e6e5906bSpbrook         ts->sim_syscalls = 1;
1849e6e5906bSpbrook     }
1850048f6b4dSbellard #elif defined(TARGET_MIPS)
1851048f6b4dSbellard     {
1852048f6b4dSbellard         int i;
1853048f6b4dSbellard 
1854*b1f9be31Sj_mayer         /* XXX: set CPU model */
1855048f6b4dSbellard         for(i = 0; i < 32; i++) {
1856048f6b4dSbellard             env->gpr[i] = regs->regs[i];
1857048f6b4dSbellard         }
1858048f6b4dSbellard         env->PC = regs->cp0_epc;
185936d23958Sths         if (env->CP0_Config1 & (1 << CP0C1_FP)) {
1860bc1ad2deSbellard             env->CP0_Status |= (1 << CP0St_CU1);
186136d23958Sths         }
1862048f6b4dSbellard     }
1863fdf9b3e8Sbellard #elif defined(TARGET_SH4)
1864fdf9b3e8Sbellard     {
1865fdf9b3e8Sbellard         int i;
1866fdf9b3e8Sbellard 
1867fdf9b3e8Sbellard         for(i = 0; i < 16; i++) {
1868fdf9b3e8Sbellard             env->gregs[i] = regs->regs[i];
1869fdf9b3e8Sbellard         }
1870fdf9b3e8Sbellard         env->pc = regs->pc;
1871fdf9b3e8Sbellard     }
1872b346ff46Sbellard #else
1873b346ff46Sbellard #error unsupported target CPU
1874b346ff46Sbellard #endif
187531e31b8aSbellard 
187674c33bedSbellard     if (gdbstub_port) {
187774c33bedSbellard         gdbserver_start (gdbstub_port);
18781fddef4bSbellard         gdb_handlesig(env, 0);
18791fddef4bSbellard     }
18801b6b029eSbellard     cpu_loop(env);
18811b6b029eSbellard     /* never exits */
188231e31b8aSbellard     return 0;
188331e31b8aSbellard }
1884