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; 37586314f2Sbellard 383a4739d6Sbellard #if defined(__i386__) && !defined(CONFIG_STATIC) 39f801f97eSbellard /* Force usage of an ELF interpreter even if it is an ELF shared 40f801f97eSbellard object ! */ 41f801f97eSbellard const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2"; 424304763bSbellard #endif 4374cd30b8Sbellard 4493ac68bcSbellard /* for recent libc, we add these dummy symbols which are not declared 4574cd30b8Sbellard when generating a linked object (bug in ld ?) */ 46fbf59244Sbellard #if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC) 47c6981055Sbellard long __preinit_array_start[0]; 48c6981055Sbellard long __preinit_array_end[0]; 4974cd30b8Sbellard long __init_array_start[0]; 5074cd30b8Sbellard long __init_array_end[0]; 5174cd30b8Sbellard long __fini_array_start[0]; 5274cd30b8Sbellard long __fini_array_end[0]; 5374cd30b8Sbellard #endif 5474cd30b8Sbellard 559de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so 569de5e440Sbellard we allocate a bigger stack. Need a better solution, for example 579de5e440Sbellard by remapping the process stack directly at the right place */ 589de5e440Sbellard unsigned long x86_stack_size = 512 * 1024; 5931e31b8aSbellard 6031e31b8aSbellard void gemu_log(const char *fmt, ...) 6131e31b8aSbellard { 6231e31b8aSbellard va_list ap; 6331e31b8aSbellard 6431e31b8aSbellard va_start(ap, fmt); 6531e31b8aSbellard vfprintf(stderr, fmt, ap); 6631e31b8aSbellard va_end(ap); 6731e31b8aSbellard } 6831e31b8aSbellard 6961190b14Sbellard void cpu_outb(CPUState *env, int addr, int val) 70367e86e8Sbellard { 71367e86e8Sbellard fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val); 72367e86e8Sbellard } 73367e86e8Sbellard 7461190b14Sbellard void cpu_outw(CPUState *env, int addr, int val) 75367e86e8Sbellard { 76367e86e8Sbellard fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val); 77367e86e8Sbellard } 78367e86e8Sbellard 7961190b14Sbellard void cpu_outl(CPUState *env, int addr, int val) 80367e86e8Sbellard { 81367e86e8Sbellard fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val); 82367e86e8Sbellard } 83367e86e8Sbellard 8461190b14Sbellard int cpu_inb(CPUState *env, int addr) 85367e86e8Sbellard { 86367e86e8Sbellard fprintf(stderr, "inb: port=0x%04x\n", addr); 87367e86e8Sbellard return 0; 88367e86e8Sbellard } 89367e86e8Sbellard 9061190b14Sbellard int cpu_inw(CPUState *env, int addr) 91367e86e8Sbellard { 92367e86e8Sbellard fprintf(stderr, "inw: port=0x%04x\n", addr); 93367e86e8Sbellard return 0; 94367e86e8Sbellard } 95367e86e8Sbellard 9661190b14Sbellard int cpu_inl(CPUState *env, int addr) 97367e86e8Sbellard { 98367e86e8Sbellard fprintf(stderr, "inl: port=0x%04x\n", addr); 99367e86e8Sbellard return 0; 100367e86e8Sbellard } 101367e86e8Sbellard 102a541f297Sbellard int cpu_get_pic_interrupt(CPUState *env) 10392ccca6aSbellard { 10492ccca6aSbellard return -1; 10592ccca6aSbellard } 10692ccca6aSbellard 10728ab0e2eSbellard /* timers for rdtsc */ 10828ab0e2eSbellard 10928ab0e2eSbellard #if defined(__i386__) 11028ab0e2eSbellard 11128ab0e2eSbellard int64_t cpu_get_real_ticks(void) 11228ab0e2eSbellard { 11328ab0e2eSbellard int64_t val; 11428ab0e2eSbellard asm volatile ("rdtsc" : "=A" (val)); 11528ab0e2eSbellard return val; 11628ab0e2eSbellard } 11728ab0e2eSbellard 11828ab0e2eSbellard #elif defined(__x86_64__) 11928ab0e2eSbellard 12028ab0e2eSbellard int64_t cpu_get_real_ticks(void) 12128ab0e2eSbellard { 12228ab0e2eSbellard uint32_t low,high; 12328ab0e2eSbellard int64_t val; 12428ab0e2eSbellard asm volatile("rdtsc" : "=a" (low), "=d" (high)); 12528ab0e2eSbellard val = high; 12628ab0e2eSbellard val <<= 32; 12728ab0e2eSbellard val |= low; 12828ab0e2eSbellard return val; 12928ab0e2eSbellard } 13028ab0e2eSbellard 13128ab0e2eSbellard #else 13228ab0e2eSbellard 13328ab0e2eSbellard static uint64_t emu_time; 13428ab0e2eSbellard 13528ab0e2eSbellard int64_t cpu_get_real_ticks(void) 13628ab0e2eSbellard { 13728ab0e2eSbellard return emu_time++; 13828ab0e2eSbellard } 13928ab0e2eSbellard 14028ab0e2eSbellard #endif 14128ab0e2eSbellard 142a541f297Sbellard #ifdef TARGET_I386 143a541f297Sbellard /***********************************************************/ 144a541f297Sbellard /* CPUX86 core interface */ 145a541f297Sbellard 14628ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env) 14728ab0e2eSbellard { 14828ab0e2eSbellard return cpu_get_real_ticks(); 14928ab0e2eSbellard } 15028ab0e2eSbellard 151f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 152f4beb510Sbellard int flags) 1536dbad63eSbellard { 154f4beb510Sbellard unsigned int e1, e2; 1556dbad63eSbellard e1 = (addr << 16) | (limit & 0xffff); 1566dbad63eSbellard e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); 157f4beb510Sbellard e2 |= flags; 158f4beb510Sbellard stl((uint8_t *)ptr, e1); 159f4beb510Sbellard stl((uint8_t *)ptr + 4, e2); 160f4beb510Sbellard } 161f4beb510Sbellard 162f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 163f4beb510Sbellard unsigned long addr, unsigned int sel) 164f4beb510Sbellard { 165f4beb510Sbellard unsigned int e1, e2; 166f4beb510Sbellard e1 = (addr & 0xffff) | (sel << 16); 167f4beb510Sbellard e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 1686dbad63eSbellard stl((uint8_t *)ptr, e1); 1696dbad63eSbellard stl((uint8_t *)ptr + 4, e2); 1706dbad63eSbellard } 1716dbad63eSbellard 1726dbad63eSbellard uint64_t gdt_table[6]; 173f4beb510Sbellard uint64_t idt_table[256]; 174f4beb510Sbellard 175f4beb510Sbellard /* only dpl matters as we do only user space emulation */ 176f4beb510Sbellard static void set_idt(int n, unsigned int dpl) 177f4beb510Sbellard { 178f4beb510Sbellard set_gate(idt_table + n, 0, dpl, 0, 0); 179f4beb510Sbellard } 18031e31b8aSbellard 18189e957e7Sbellard void cpu_loop(CPUX86State *env) 182bc8a22ccSbellard { 183bc8a22ccSbellard int trapnr; 18480a9d035Sbellard target_ulong pc; 185bc8a22ccSbellard target_siginfo_t info; 186bc8a22ccSbellard 187bc8a22ccSbellard for(;;) { 188bc8a22ccSbellard trapnr = cpu_x86_exec(env); 189bc8a22ccSbellard switch(trapnr) { 190f4beb510Sbellard case 0x80: 191f4beb510Sbellard /* linux syscall */ 1921b6b029eSbellard env->regs[R_EAX] = do_syscall(env, 1931b6b029eSbellard env->regs[R_EAX], 1941b6b029eSbellard env->regs[R_EBX], 1951b6b029eSbellard env->regs[R_ECX], 1961b6b029eSbellard env->regs[R_EDX], 1971b6b029eSbellard env->regs[R_ESI], 1981b6b029eSbellard env->regs[R_EDI], 1991b6b029eSbellard env->regs[R_EBP]); 200f4beb510Sbellard break; 201f4beb510Sbellard case EXCP0B_NOSEG: 202f4beb510Sbellard case EXCP0C_STACK: 203f4beb510Sbellard info.si_signo = SIGBUS; 204f4beb510Sbellard info.si_errno = 0; 205f4beb510Sbellard info.si_code = TARGET_SI_KERNEL; 206f4beb510Sbellard info._sifields._sigfault._addr = 0; 207f4beb510Sbellard queue_signal(info.si_signo, &info); 208f4beb510Sbellard break; 209f4beb510Sbellard case EXCP0D_GPF: 210f4beb510Sbellard if (env->eflags & VM_MASK) { 211f4beb510Sbellard handle_vm86_fault(env); 2121b6b029eSbellard } else { 2139de5e440Sbellard info.si_signo = SIGSEGV; 2149de5e440Sbellard info.si_errno = 0; 215b689bc57Sbellard info.si_code = TARGET_SI_KERNEL; 2169de5e440Sbellard info._sifields._sigfault._addr = 0; 2179de5e440Sbellard queue_signal(info.si_signo, &info); 2181b6b029eSbellard } 2191b6b029eSbellard break; 220b689bc57Sbellard case EXCP0E_PAGE: 221b689bc57Sbellard info.si_signo = SIGSEGV; 222b689bc57Sbellard info.si_errno = 0; 223b689bc57Sbellard if (!(env->error_code & 1)) 224b689bc57Sbellard info.si_code = TARGET_SEGV_MAPERR; 225b689bc57Sbellard else 226b689bc57Sbellard info.si_code = TARGET_SEGV_ACCERR; 227970a87a6Sbellard info._sifields._sigfault._addr = env->cr[2]; 228b689bc57Sbellard queue_signal(info.si_signo, &info); 229b689bc57Sbellard break; 2309de5e440Sbellard case EXCP00_DIVZ: 231bc8a22ccSbellard if (env->eflags & VM_MASK) { 232447db213Sbellard handle_vm86_trap(env, trapnr); 233bc8a22ccSbellard } else { 2349de5e440Sbellard /* division by zero */ 2359de5e440Sbellard info.si_signo = SIGFPE; 2369de5e440Sbellard info.si_errno = 0; 2379de5e440Sbellard info.si_code = TARGET_FPE_INTDIV; 2389de5e440Sbellard info._sifields._sigfault._addr = env->eip; 2399de5e440Sbellard queue_signal(info.si_signo, &info); 240bc8a22ccSbellard } 2419de5e440Sbellard break; 242447db213Sbellard case EXCP01_SSTP: 243447db213Sbellard case EXCP03_INT3: 244447db213Sbellard if (env->eflags & VM_MASK) { 245447db213Sbellard handle_vm86_trap(env, trapnr); 246447db213Sbellard } else { 247447db213Sbellard info.si_signo = SIGTRAP; 248447db213Sbellard info.si_errno = 0; 249447db213Sbellard if (trapnr == EXCP01_SSTP) { 250447db213Sbellard info.si_code = TARGET_TRAP_BRKPT; 251447db213Sbellard info._sifields._sigfault._addr = env->eip; 252447db213Sbellard } else { 253447db213Sbellard info.si_code = TARGET_SI_KERNEL; 254447db213Sbellard info._sifields._sigfault._addr = 0; 255447db213Sbellard } 256447db213Sbellard queue_signal(info.si_signo, &info); 257447db213Sbellard } 258447db213Sbellard break; 2599de5e440Sbellard case EXCP04_INTO: 2609de5e440Sbellard case EXCP05_BOUND: 261bc8a22ccSbellard if (env->eflags & VM_MASK) { 262447db213Sbellard handle_vm86_trap(env, trapnr); 263bc8a22ccSbellard } else { 2649de5e440Sbellard info.si_signo = SIGSEGV; 2659de5e440Sbellard info.si_errno = 0; 266b689bc57Sbellard info.si_code = TARGET_SI_KERNEL; 2679de5e440Sbellard info._sifields._sigfault._addr = 0; 2689de5e440Sbellard queue_signal(info.si_signo, &info); 269bc8a22ccSbellard } 2709de5e440Sbellard break; 2719de5e440Sbellard case EXCP06_ILLOP: 2729de5e440Sbellard info.si_signo = SIGILL; 2739de5e440Sbellard info.si_errno = 0; 2749de5e440Sbellard info.si_code = TARGET_ILL_ILLOPN; 2759de5e440Sbellard info._sifields._sigfault._addr = env->eip; 2769de5e440Sbellard queue_signal(info.si_signo, &info); 2779de5e440Sbellard break; 2789de5e440Sbellard case EXCP_INTERRUPT: 2799de5e440Sbellard /* just indicate that signals should be handled asap */ 2809de5e440Sbellard break; 2811fddef4bSbellard case EXCP_DEBUG: 2821fddef4bSbellard { 2831fddef4bSbellard int sig; 2841fddef4bSbellard 2851fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 2861fddef4bSbellard if (sig) 2871fddef4bSbellard { 2881fddef4bSbellard info.si_signo = sig; 2891fddef4bSbellard info.si_errno = 0; 2901fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 2911fddef4bSbellard queue_signal(info.si_signo, &info); 2921fddef4bSbellard } 2931fddef4bSbellard } 2941fddef4bSbellard break; 2951b6b029eSbellard default: 296970a87a6Sbellard pc = env->segs[R_CS].base + env->eip; 297bc8a22ccSbellard fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 298bc8a22ccSbellard (long)pc, trapnr); 2991b6b029eSbellard abort(); 3001b6b029eSbellard } 30166fb9763Sbellard process_pending_signals(env); 3021b6b029eSbellard } 3031b6b029eSbellard } 304b346ff46Sbellard #endif 305b346ff46Sbellard 306b346ff46Sbellard #ifdef TARGET_ARM 307b346ff46Sbellard 3086f1f31c0Sbellard /* XXX: find a better solution */ 3096f1f31c0Sbellard extern void tb_invalidate_page_range(target_ulong start, target_ulong end); 3106f1f31c0Sbellard 3116f1f31c0Sbellard static void arm_cache_flush(target_ulong start, target_ulong last) 3126f1f31c0Sbellard { 3136f1f31c0Sbellard target_ulong addr, last1; 3146f1f31c0Sbellard 3156f1f31c0Sbellard if (last < start) 3166f1f31c0Sbellard return; 3176f1f31c0Sbellard addr = start; 3186f1f31c0Sbellard for(;;) { 3196f1f31c0Sbellard last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1; 3206f1f31c0Sbellard if (last1 > last) 3216f1f31c0Sbellard last1 = last; 3226f1f31c0Sbellard tb_invalidate_page_range(addr, last1 + 1); 3236f1f31c0Sbellard if (last1 == last) 3246f1f31c0Sbellard break; 3256f1f31c0Sbellard addr = last1 + 1; 3266f1f31c0Sbellard } 3276f1f31c0Sbellard } 3286f1f31c0Sbellard 329b346ff46Sbellard void cpu_loop(CPUARMState *env) 330b346ff46Sbellard { 331b346ff46Sbellard int trapnr; 332b346ff46Sbellard unsigned int n, insn; 333b346ff46Sbellard target_siginfo_t info; 334b346ff46Sbellard 335b346ff46Sbellard for(;;) { 336b346ff46Sbellard trapnr = cpu_arm_exec(env); 337b346ff46Sbellard switch(trapnr) { 338b346ff46Sbellard case EXCP_UDEF: 339c6981055Sbellard { 340c6981055Sbellard TaskState *ts = env->opaque; 341c6981055Sbellard uint32_t opcode; 342c6981055Sbellard 343c6981055Sbellard /* we handle the FPU emulation here, as Linux */ 344c6981055Sbellard /* we get the opcode */ 345c6981055Sbellard opcode = ldl_raw((uint8_t *)env->regs[15]); 346c6981055Sbellard 347c6981055Sbellard if (EmulateAll(opcode, &ts->fpa, env->regs) == 0) { 348b346ff46Sbellard info.si_signo = SIGILL; 349b346ff46Sbellard info.si_errno = 0; 350b346ff46Sbellard info.si_code = TARGET_ILL_ILLOPN; 351b346ff46Sbellard info._sifields._sigfault._addr = env->regs[15]; 352b346ff46Sbellard queue_signal(info.si_signo, &info); 353c6981055Sbellard } else { 354c6981055Sbellard /* increment PC */ 355c6981055Sbellard env->regs[15] += 4; 356c6981055Sbellard } 357c6981055Sbellard } 358b346ff46Sbellard break; 359b346ff46Sbellard case EXCP_SWI: 360b346ff46Sbellard { 361b346ff46Sbellard /* system call */ 362192c7bd9Sbellard if (env->thumb) { 363192c7bd9Sbellard insn = lduw((void *)(env->regs[15] - 2)); 364192c7bd9Sbellard n = insn & 0xff; 365192c7bd9Sbellard } else { 366b346ff46Sbellard insn = ldl((void *)(env->regs[15] - 4)); 367b346ff46Sbellard n = insn & 0xffffff; 368192c7bd9Sbellard } 369192c7bd9Sbellard 3706f1f31c0Sbellard if (n == ARM_NR_cacheflush) { 3716f1f31c0Sbellard arm_cache_flush(env->regs[0], env->regs[1]); 372a4f81979Sbellard } else if (n == ARM_NR_semihosting 373a4f81979Sbellard || n == ARM_NR_thumb_semihosting) { 374a4f81979Sbellard env->regs[0] = do_arm_semihosting (env); 375192c7bd9Sbellard } else if (n >= ARM_SYSCALL_BASE 376192c7bd9Sbellard || (env->thumb && n == ARM_THUMB_SYSCALL)) { 377b346ff46Sbellard /* linux syscall */ 378192c7bd9Sbellard if (env->thumb) { 379192c7bd9Sbellard n = env->regs[7]; 380192c7bd9Sbellard } else { 381b346ff46Sbellard n -= ARM_SYSCALL_BASE; 382192c7bd9Sbellard } 383b346ff46Sbellard env->regs[0] = do_syscall(env, 384b346ff46Sbellard n, 385b346ff46Sbellard env->regs[0], 386b346ff46Sbellard env->regs[1], 387b346ff46Sbellard env->regs[2], 388b346ff46Sbellard env->regs[3], 389b346ff46Sbellard env->regs[4], 390e1a2849cSbellard env->regs[5]); 391b346ff46Sbellard } else { 392b346ff46Sbellard goto error; 393b346ff46Sbellard } 394b346ff46Sbellard } 395b346ff46Sbellard break; 39643fff238Sbellard case EXCP_INTERRUPT: 39743fff238Sbellard /* just indicate that signals should be handled asap */ 39843fff238Sbellard break; 39968016c62Sbellard case EXCP_PREFETCH_ABORT: 40068016c62Sbellard case EXCP_DATA_ABORT: 40168016c62Sbellard { 40268016c62Sbellard info.si_signo = SIGSEGV; 40368016c62Sbellard info.si_errno = 0; 40468016c62Sbellard /* XXX: check env->error_code */ 40568016c62Sbellard info.si_code = TARGET_SEGV_MAPERR; 40668016c62Sbellard info._sifields._sigfault._addr = env->cp15_6; 40768016c62Sbellard queue_signal(info.si_signo, &info); 40868016c62Sbellard } 40968016c62Sbellard break; 4101fddef4bSbellard case EXCP_DEBUG: 4111fddef4bSbellard { 4121fddef4bSbellard int sig; 4131fddef4bSbellard 4141fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 4151fddef4bSbellard if (sig) 4161fddef4bSbellard { 4171fddef4bSbellard info.si_signo = sig; 4181fddef4bSbellard info.si_errno = 0; 4191fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 4201fddef4bSbellard queue_signal(info.si_signo, &info); 4211fddef4bSbellard } 4221fddef4bSbellard } 4231fddef4bSbellard break; 424b346ff46Sbellard default: 425b346ff46Sbellard error: 426b346ff46Sbellard fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 427b346ff46Sbellard trapnr); 4287fe48483Sbellard cpu_dump_state(env, stderr, fprintf, 0); 429b346ff46Sbellard abort(); 430b346ff46Sbellard } 431b346ff46Sbellard process_pending_signals(env); 432b346ff46Sbellard } 433b346ff46Sbellard } 434b346ff46Sbellard 435b346ff46Sbellard #endif 4361b6b029eSbellard 43793ac68bcSbellard #ifdef TARGET_SPARC 43893ac68bcSbellard 439060366c5Sbellard //#define DEBUG_WIN 440060366c5Sbellard 4412623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info 4422623cbafSbellard can be found at http://www.sics.se/~psm/sparcstack.html */ 443060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) 444060366c5Sbellard { 445060366c5Sbellard index = (index + cwp * 16) & (16 * NWINDOWS - 1); 446060366c5Sbellard /* wrap handling : if cwp is on the last window, then we use the 447060366c5Sbellard registers 'after' the end */ 448060366c5Sbellard if (index < 8 && env->cwp == (NWINDOWS - 1)) 449060366c5Sbellard index += (16 * NWINDOWS); 450060366c5Sbellard return index; 451060366c5Sbellard } 452060366c5Sbellard 4532623cbafSbellard /* save the register window 'cwp1' */ 4542623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1) 455060366c5Sbellard { 4562623cbafSbellard unsigned int i; 457060366c5Sbellard uint32_t *sp_ptr; 458060366c5Sbellard 459060366c5Sbellard sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); 460060366c5Sbellard #if defined(DEBUG_WIN) 461060366c5Sbellard printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", 462060366c5Sbellard (int)sp_ptr, cwp1); 463060366c5Sbellard #endif 4642623cbafSbellard for(i = 0; i < 16; i++) { 4652623cbafSbellard put_user(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); 4662623cbafSbellard sp_ptr++; 4672623cbafSbellard } 468060366c5Sbellard } 469060366c5Sbellard 470060366c5Sbellard static void save_window(CPUSPARCState *env) 471060366c5Sbellard { 4722623cbafSbellard unsigned int new_wim; 4732623cbafSbellard new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & 4742623cbafSbellard ((1LL << NWINDOWS) - 1); 4752623cbafSbellard save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1)); 4762623cbafSbellard env->wim = new_wim; 477060366c5Sbellard } 478060366c5Sbellard 479060366c5Sbellard static void restore_window(CPUSPARCState *env) 480060366c5Sbellard { 481060366c5Sbellard unsigned int new_wim, i, cwp1; 4822623cbafSbellard uint32_t *sp_ptr, reg; 483060366c5Sbellard 484060366c5Sbellard new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & 485060366c5Sbellard ((1LL << NWINDOWS) - 1); 486060366c5Sbellard 487060366c5Sbellard /* restore the invalid window */ 488060366c5Sbellard cwp1 = (env->cwp + 1) & (NWINDOWS - 1); 489060366c5Sbellard sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); 490060366c5Sbellard #if defined(DEBUG_WIN) 491060366c5Sbellard printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", 492060366c5Sbellard (int)sp_ptr, cwp1); 493060366c5Sbellard #endif 4942623cbafSbellard for(i = 0; i < 16; i++) { 4952623cbafSbellard get_user(reg, sp_ptr); 4962623cbafSbellard env->regbase[get_reg_index(env, cwp1, 8 + i)] = reg; 4972623cbafSbellard sp_ptr++; 4982623cbafSbellard } 499060366c5Sbellard env->wim = new_wim; 500060366c5Sbellard } 501060366c5Sbellard 502060366c5Sbellard static void flush_windows(CPUSPARCState *env) 503060366c5Sbellard { 504060366c5Sbellard int offset, cwp1; 5052623cbafSbellard 5062623cbafSbellard offset = 1; 507060366c5Sbellard for(;;) { 508060366c5Sbellard /* if restore would invoke restore_window(), then we can stop */ 5092623cbafSbellard cwp1 = (env->cwp + offset) & (NWINDOWS - 1); 510060366c5Sbellard if (env->wim & (1 << cwp1)) 511060366c5Sbellard break; 5122623cbafSbellard save_window_offset(env, cwp1); 513060366c5Sbellard offset++; 514060366c5Sbellard } 5152623cbafSbellard /* set wim so that restore will reload the registers */ 5162623cbafSbellard cwp1 = (env->cwp + 1) & (NWINDOWS - 1); 5172623cbafSbellard env->wim = 1 << cwp1; 5182623cbafSbellard #if defined(DEBUG_WIN) 5192623cbafSbellard printf("flush_windows: nb=%d\n", offset - 1); 52080a9d035Sbellard #endif 5212623cbafSbellard } 522060366c5Sbellard 52393ac68bcSbellard void cpu_loop (CPUSPARCState *env) 52493ac68bcSbellard { 525060366c5Sbellard int trapnr, ret; 52661ff6f58Sbellard target_siginfo_t info; 52793ac68bcSbellard 52893ac68bcSbellard while (1) { 52993ac68bcSbellard trapnr = cpu_sparc_exec (env); 53093ac68bcSbellard 53193ac68bcSbellard switch (trapnr) { 532060366c5Sbellard case 0x88: 533060366c5Sbellard case 0x90: 534060366c5Sbellard ret = do_syscall (env, env->gregs[1], 535060366c5Sbellard env->regwptr[0], env->regwptr[1], 536060366c5Sbellard env->regwptr[2], env->regwptr[3], 537060366c5Sbellard env->regwptr[4], env->regwptr[5]); 538060366c5Sbellard if ((unsigned int)ret >= (unsigned int)(-515)) { 53993ac68bcSbellard env->psr |= PSR_CARRY; 540060366c5Sbellard ret = -ret; 541060366c5Sbellard } else { 542060366c5Sbellard env->psr &= ~PSR_CARRY; 543060366c5Sbellard } 544060366c5Sbellard env->regwptr[0] = ret; 545060366c5Sbellard /* next instruction */ 546060366c5Sbellard env->pc = env->npc; 547060366c5Sbellard env->npc = env->npc + 4; 548060366c5Sbellard break; 549060366c5Sbellard case 0x83: /* flush windows */ 5502623cbafSbellard flush_windows(env); 551060366c5Sbellard /* next instruction */ 552060366c5Sbellard env->pc = env->npc; 553060366c5Sbellard env->npc = env->npc + 4; 554060366c5Sbellard break; 5553475187dSbellard #ifndef TARGET_SPARC64 556060366c5Sbellard case TT_WIN_OVF: /* window overflow */ 557060366c5Sbellard save_window(env); 558060366c5Sbellard break; 559060366c5Sbellard case TT_WIN_UNF: /* window underflow */ 560060366c5Sbellard restore_window(env); 56193ac68bcSbellard break; 56261ff6f58Sbellard case TT_TFAULT: 56361ff6f58Sbellard case TT_DFAULT: 56461ff6f58Sbellard { 56561ff6f58Sbellard info.si_signo = SIGSEGV; 56661ff6f58Sbellard info.si_errno = 0; 56761ff6f58Sbellard /* XXX: check env->error_code */ 56861ff6f58Sbellard info.si_code = TARGET_SEGV_MAPERR; 56961ff6f58Sbellard info._sifields._sigfault._addr = env->mmuregs[4]; 57061ff6f58Sbellard queue_signal(info.si_signo, &info); 57161ff6f58Sbellard } 57261ff6f58Sbellard break; 5733475187dSbellard #else 5743475187dSbellard // XXX 5753475187dSbellard #endif 576e80cfcfcSbellard case 0x100: // XXX, why do we get these? 577e80cfcfcSbellard break; 5781fddef4bSbellard case EXCP_DEBUG: 5791fddef4bSbellard { 5801fddef4bSbellard int sig; 5811fddef4bSbellard 5821fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 5831fddef4bSbellard if (sig) 5841fddef4bSbellard { 5851fddef4bSbellard info.si_signo = sig; 5861fddef4bSbellard info.si_errno = 0; 5871fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 5881fddef4bSbellard queue_signal(info.si_signo, &info); 5891fddef4bSbellard } 5901fddef4bSbellard } 5911fddef4bSbellard break; 59293ac68bcSbellard default: 593060366c5Sbellard printf ("Unhandled trap: 0x%x\n", trapnr); 5947fe48483Sbellard cpu_dump_state(env, stderr, fprintf, 0); 59593ac68bcSbellard exit (1); 59693ac68bcSbellard } 59793ac68bcSbellard process_pending_signals (env); 59893ac68bcSbellard } 59993ac68bcSbellard } 60093ac68bcSbellard 60193ac68bcSbellard #endif 60293ac68bcSbellard 60367867308Sbellard #ifdef TARGET_PPC 6049fddaa0cSbellard 6059fddaa0cSbellard static inline uint64_t cpu_ppc_get_tb (CPUState *env) 6069fddaa0cSbellard { 6079fddaa0cSbellard /* TO FIX */ 6089fddaa0cSbellard return 0; 6099fddaa0cSbellard } 6109fddaa0cSbellard 6119fddaa0cSbellard uint32_t cpu_ppc_load_tbl (CPUState *env) 6129fddaa0cSbellard { 6139fddaa0cSbellard return cpu_ppc_get_tb(env) & 0xFFFFFFFF; 6149fddaa0cSbellard } 6159fddaa0cSbellard 6169fddaa0cSbellard uint32_t cpu_ppc_load_tbu (CPUState *env) 6179fddaa0cSbellard { 6189fddaa0cSbellard return cpu_ppc_get_tb(env) >> 32; 6199fddaa0cSbellard } 6209fddaa0cSbellard 6219fddaa0cSbellard static void cpu_ppc_store_tb (CPUState *env, uint64_t value) 6229fddaa0cSbellard { 6239fddaa0cSbellard /* TO FIX */ 6249fddaa0cSbellard } 6259fddaa0cSbellard 6269fddaa0cSbellard void cpu_ppc_store_tbu (CPUState *env, uint32_t value) 6279fddaa0cSbellard { 6289fddaa0cSbellard cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); 6299fddaa0cSbellard } 6309fddaa0cSbellard 6319fddaa0cSbellard void cpu_ppc_store_tbl (CPUState *env, uint32_t value) 6329fddaa0cSbellard { 6339fddaa0cSbellard cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); 6349fddaa0cSbellard } 6359fddaa0cSbellard 6369fddaa0cSbellard uint32_t cpu_ppc_load_decr (CPUState *env) 6379fddaa0cSbellard { 6389fddaa0cSbellard /* TO FIX */ 6399fddaa0cSbellard return -1; 6409fddaa0cSbellard } 6419fddaa0cSbellard 6429fddaa0cSbellard void cpu_ppc_store_decr (CPUState *env, uint32_t value) 6439fddaa0cSbellard { 6449fddaa0cSbellard /* TO FIX */ 6459fddaa0cSbellard } 6469fddaa0cSbellard 64767867308Sbellard void cpu_loop(CPUPPCState *env) 64867867308Sbellard { 64967867308Sbellard target_siginfo_t info; 65061190b14Sbellard int trapnr; 65161190b14Sbellard uint32_t ret; 65267867308Sbellard 65367867308Sbellard for(;;) { 65467867308Sbellard trapnr = cpu_ppc_exec(env); 65561190b14Sbellard if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH && 65661190b14Sbellard trapnr != EXCP_TRACE) { 65761190b14Sbellard if (loglevel > 0) { 6587fe48483Sbellard cpu_dump_state(env, logfile, fprintf, 0); 65961190b14Sbellard } 66061190b14Sbellard } 66167867308Sbellard switch(trapnr) { 66267867308Sbellard case EXCP_NONE: 66367867308Sbellard break; 66461190b14Sbellard case EXCP_SYSCALL_USER: 66567867308Sbellard /* system call */ 66667867308Sbellard /* WARNING: 66767867308Sbellard * PPC ABI uses overflow flag in cr0 to signal an error 66867867308Sbellard * in syscalls. 66967867308Sbellard */ 67061190b14Sbellard #if 0 67161190b14Sbellard printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0], 67261190b14Sbellard env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]); 67361190b14Sbellard #endif 67467867308Sbellard env->crf[0] &= ~0x1; 67567867308Sbellard ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], 67667867308Sbellard env->gpr[5], env->gpr[6], env->gpr[7], 67767867308Sbellard env->gpr[8]); 67867867308Sbellard if (ret > (uint32_t)(-515)) { 67967867308Sbellard env->crf[0] |= 0x1; 68067867308Sbellard ret = -ret; 68167867308Sbellard } 68267867308Sbellard env->gpr[3] = ret; 68361190b14Sbellard #if 0 68461190b14Sbellard printf("syscall returned 0x%08x (%d)\n", ret, ret); 68561190b14Sbellard #endif 68661190b14Sbellard break; 68761190b14Sbellard case EXCP_RESET: 68861190b14Sbellard /* Should not happen ! */ 68961190b14Sbellard fprintf(stderr, "RESET asked... Stop emulation\n"); 69061190b14Sbellard if (loglevel) 69161190b14Sbellard fprintf(logfile, "RESET asked... Stop emulation\n"); 69261190b14Sbellard abort(); 69361190b14Sbellard case EXCP_MACHINE_CHECK: 69461190b14Sbellard fprintf(stderr, "Machine check exeption... Stop emulation\n"); 69561190b14Sbellard if (loglevel) 69661190b14Sbellard fprintf(logfile, "RESET asked... Stop emulation\n"); 69761190b14Sbellard info.si_signo = TARGET_SIGBUS; 69861190b14Sbellard info.si_errno = 0; 69961190b14Sbellard info.si_code = TARGET_BUS_OBJERR; 70061190b14Sbellard info._sifields._sigfault._addr = env->nip - 4; 70161190b14Sbellard queue_signal(info.si_signo, &info); 70261190b14Sbellard case EXCP_DSI: 7033fc6c082Sbellard fprintf(stderr, "Invalid data memory access: 0x%08x\n", 7043fc6c082Sbellard env->spr[SPR_DAR]); 70561190b14Sbellard if (loglevel) { 70661190b14Sbellard fprintf(logfile, "Invalid data memory access: 0x%08x\n", 7073fc6c082Sbellard env->spr[SPR_DAR]); 70861190b14Sbellard } 709*2be0071fSbellard switch (env->error_code & 0xFF000000) { 710*2be0071fSbellard case 0x40000000: 71161190b14Sbellard info.si_signo = TARGET_SIGSEGV; 71261190b14Sbellard info.si_errno = 0; 71361190b14Sbellard info.si_code = TARGET_SEGV_MAPERR; 71461190b14Sbellard break; 715*2be0071fSbellard case 0x04000000: 71661190b14Sbellard info.si_signo = TARGET_SIGILL; 71761190b14Sbellard info.si_errno = 0; 71861190b14Sbellard info.si_code = TARGET_ILL_ILLADR; 71961190b14Sbellard break; 720*2be0071fSbellard case 0x08000000: 72161190b14Sbellard info.si_signo = TARGET_SIGSEGV; 72261190b14Sbellard info.si_errno = 0; 72361190b14Sbellard info.si_code = TARGET_SEGV_ACCERR; 72461190b14Sbellard break; 72561190b14Sbellard default: 72661190b14Sbellard /* Let's send a regular segfault... */ 72761190b14Sbellard fprintf(stderr, "Invalid segfault errno (%02x)\n", 72861190b14Sbellard env->error_code); 72961190b14Sbellard if (loglevel) { 73061190b14Sbellard fprintf(logfile, "Invalid segfault errno (%02x)\n", 73161190b14Sbellard env->error_code); 73261190b14Sbellard } 73361190b14Sbellard info.si_signo = TARGET_SIGSEGV; 73461190b14Sbellard info.si_errno = 0; 73561190b14Sbellard info.si_code = TARGET_SEGV_MAPERR; 73667867308Sbellard break; 73767867308Sbellard } 73861190b14Sbellard info._sifields._sigfault._addr = env->nip; 73961190b14Sbellard queue_signal(info.si_signo, &info); 74061190b14Sbellard break; 74161190b14Sbellard case EXCP_ISI: 74261190b14Sbellard fprintf(stderr, "Invalid instruction fetch\n"); 74361190b14Sbellard if (loglevel) 74461190b14Sbellard fprintf(logfile, "Invalid instruction fetch\n"); 745*2be0071fSbellard switch (env->error_code & 0xFF000000) { 746*2be0071fSbellard case 0x40000000: 74761190b14Sbellard info.si_signo = TARGET_SIGSEGV; 74861190b14Sbellard info.si_errno = 0; 74961190b14Sbellard info.si_code = TARGET_SEGV_MAPERR; 75061190b14Sbellard break; 751*2be0071fSbellard case 0x10000000: 752*2be0071fSbellard case 0x08000000: 75361190b14Sbellard info.si_signo = TARGET_SIGSEGV; 75461190b14Sbellard info.si_errno = 0; 75561190b14Sbellard info.si_code = TARGET_SEGV_ACCERR; 75661190b14Sbellard break; 75767867308Sbellard default: 75861190b14Sbellard /* Let's send a regular segfault... */ 75961190b14Sbellard fprintf(stderr, "Invalid segfault errno (%02x)\n", 76061190b14Sbellard env->error_code); 76161190b14Sbellard if (loglevel) { 76261190b14Sbellard fprintf(logfile, "Invalid segfault errno (%02x)\n", 76361190b14Sbellard env->error_code); 76461190b14Sbellard } 76561190b14Sbellard info.si_signo = TARGET_SIGSEGV; 76661190b14Sbellard info.si_errno = 0; 76761190b14Sbellard info.si_code = TARGET_SEGV_MAPERR; 76861190b14Sbellard break; 76961190b14Sbellard } 77061190b14Sbellard info._sifields._sigfault._addr = env->nip - 4; 77161190b14Sbellard queue_signal(info.si_signo, &info); 77261190b14Sbellard break; 77361190b14Sbellard case EXCP_EXTERNAL: 77461190b14Sbellard /* Should not happen ! */ 77561190b14Sbellard fprintf(stderr, "External interruption... Stop emulation\n"); 77661190b14Sbellard if (loglevel) 77761190b14Sbellard fprintf(logfile, "External interruption... Stop emulation\n"); 77861190b14Sbellard abort(); 77961190b14Sbellard case EXCP_ALIGN: 78061190b14Sbellard fprintf(stderr, "Invalid unaligned memory access\n"); 78161190b14Sbellard if (loglevel) 78261190b14Sbellard fprintf(logfile, "Invalid unaligned memory access\n"); 78361190b14Sbellard info.si_signo = TARGET_SIGBUS; 78461190b14Sbellard info.si_errno = 0; 78561190b14Sbellard info.si_code = TARGET_BUS_ADRALN; 78661190b14Sbellard info._sifields._sigfault._addr = env->nip - 4; 78761190b14Sbellard queue_signal(info.si_signo, &info); 78861190b14Sbellard break; 78961190b14Sbellard case EXCP_PROGRAM: 79061190b14Sbellard switch (env->error_code & ~0xF) { 79161190b14Sbellard case EXCP_FP: 79261190b14Sbellard fprintf(stderr, "Program exception\n"); 79361190b14Sbellard if (loglevel) 79461190b14Sbellard fprintf(logfile, "Program exception\n"); 79561190b14Sbellard /* Set FX */ 79661190b14Sbellard env->fpscr[7] |= 0x8; 79761190b14Sbellard /* Finally, update FEX */ 79861190b14Sbellard if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) & 79961190b14Sbellard ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3))) 80061190b14Sbellard env->fpscr[7] |= 0x4; 80161190b14Sbellard info.si_signo = TARGET_SIGFPE; 80261190b14Sbellard info.si_errno = 0; 80361190b14Sbellard switch (env->error_code & 0xF) { 80461190b14Sbellard case EXCP_FP_OX: 80561190b14Sbellard info.si_code = TARGET_FPE_FLTOVF; 80661190b14Sbellard break; 80761190b14Sbellard case EXCP_FP_UX: 80861190b14Sbellard info.si_code = TARGET_FPE_FLTUND; 80961190b14Sbellard break; 81061190b14Sbellard case EXCP_FP_ZX: 81161190b14Sbellard case EXCP_FP_VXZDZ: 81261190b14Sbellard info.si_code = TARGET_FPE_FLTDIV; 81361190b14Sbellard break; 81461190b14Sbellard case EXCP_FP_XX: 81561190b14Sbellard info.si_code = TARGET_FPE_FLTRES; 81661190b14Sbellard break; 81761190b14Sbellard case EXCP_FP_VXSOFT: 81861190b14Sbellard info.si_code = TARGET_FPE_FLTINV; 81961190b14Sbellard break; 82061190b14Sbellard case EXCP_FP_VXNAN: 82161190b14Sbellard case EXCP_FP_VXISI: 82261190b14Sbellard case EXCP_FP_VXIDI: 82361190b14Sbellard case EXCP_FP_VXIMZ: 82461190b14Sbellard case EXCP_FP_VXVC: 82561190b14Sbellard case EXCP_FP_VXSQRT: 82661190b14Sbellard case EXCP_FP_VXCVI: 82761190b14Sbellard info.si_code = TARGET_FPE_FLTSUB; 82861190b14Sbellard break; 82961190b14Sbellard default: 83061190b14Sbellard fprintf(stderr, "Unknown floating point exception " 83161190b14Sbellard "(%02x)\n", env->error_code); 83261190b14Sbellard if (loglevel) { 83361190b14Sbellard fprintf(logfile, "Unknown floating point exception " 83461190b14Sbellard "(%02x)\n", env->error_code & 0xF); 83561190b14Sbellard } 83661190b14Sbellard } 83761190b14Sbellard break; 83861190b14Sbellard case EXCP_INVAL: 83961190b14Sbellard fprintf(stderr, "Invalid instruction\n"); 84061190b14Sbellard if (loglevel) 84161190b14Sbellard fprintf(logfile, "Invalid instruction\n"); 84261190b14Sbellard info.si_signo = TARGET_SIGILL; 84361190b14Sbellard info.si_errno = 0; 84461190b14Sbellard switch (env->error_code & 0xF) { 84561190b14Sbellard case EXCP_INVAL_INVAL: 84661190b14Sbellard info.si_code = TARGET_ILL_ILLOPC; 84761190b14Sbellard break; 84861190b14Sbellard case EXCP_INVAL_LSWX: 84961190b14Sbellard info.si_code = TARGET_ILL_ILLOPN; 85061190b14Sbellard break; 85161190b14Sbellard case EXCP_INVAL_SPR: 85261190b14Sbellard info.si_code = TARGET_ILL_PRVREG; 85361190b14Sbellard break; 85461190b14Sbellard case EXCP_INVAL_FP: 85561190b14Sbellard info.si_code = TARGET_ILL_COPROC; 85661190b14Sbellard break; 85761190b14Sbellard default: 85861190b14Sbellard fprintf(stderr, "Unknown invalid operation (%02x)\n", 85961190b14Sbellard env->error_code & 0xF); 86061190b14Sbellard if (loglevel) { 86161190b14Sbellard fprintf(logfile, "Unknown invalid operation (%02x)\n", 86261190b14Sbellard env->error_code & 0xF); 86361190b14Sbellard } 86461190b14Sbellard info.si_code = TARGET_ILL_ILLADR; 86561190b14Sbellard break; 86661190b14Sbellard } 86761190b14Sbellard break; 86861190b14Sbellard case EXCP_PRIV: 86961190b14Sbellard fprintf(stderr, "Privilege violation\n"); 87061190b14Sbellard if (loglevel) 87161190b14Sbellard fprintf(logfile, "Privilege violation\n"); 87261190b14Sbellard info.si_signo = TARGET_SIGILL; 87361190b14Sbellard info.si_errno = 0; 87461190b14Sbellard switch (env->error_code & 0xF) { 87561190b14Sbellard case EXCP_PRIV_OPC: 87661190b14Sbellard info.si_code = TARGET_ILL_PRVOPC; 87761190b14Sbellard break; 87861190b14Sbellard case EXCP_PRIV_REG: 87961190b14Sbellard info.si_code = TARGET_ILL_PRVREG; 88061190b14Sbellard break; 88161190b14Sbellard default: 88261190b14Sbellard fprintf(stderr, "Unknown privilege violation (%02x)\n", 88361190b14Sbellard env->error_code & 0xF); 88461190b14Sbellard info.si_code = TARGET_ILL_PRVOPC; 88561190b14Sbellard break; 88661190b14Sbellard } 88761190b14Sbellard break; 88861190b14Sbellard case EXCP_TRAP: 88961190b14Sbellard fprintf(stderr, "Tried to call a TRAP\n"); 89061190b14Sbellard if (loglevel) 89161190b14Sbellard fprintf(logfile, "Tried to call a TRAP\n"); 89261190b14Sbellard abort(); 89361190b14Sbellard default: 89461190b14Sbellard /* Should not happen ! */ 89561190b14Sbellard fprintf(stderr, "Unknown program exception (%02x)\n", 89661190b14Sbellard env->error_code); 89761190b14Sbellard if (loglevel) { 89861190b14Sbellard fprintf(logfile, "Unknwon program exception (%02x)\n", 89961190b14Sbellard env->error_code); 90061190b14Sbellard } 90167867308Sbellard abort(); 90267867308Sbellard } 90361190b14Sbellard info._sifields._sigfault._addr = env->nip - 4; 90461190b14Sbellard queue_signal(info.si_signo, &info); 90561190b14Sbellard break; 90661190b14Sbellard case EXCP_NO_FP: 90761190b14Sbellard fprintf(stderr, "No floating point allowed\n"); 90861190b14Sbellard if (loglevel) 90961190b14Sbellard fprintf(logfile, "No floating point allowed\n"); 91061190b14Sbellard info.si_signo = TARGET_SIGILL; 91161190b14Sbellard info.si_errno = 0; 91261190b14Sbellard info.si_code = TARGET_ILL_COPROC; 91361190b14Sbellard info._sifields._sigfault._addr = env->nip - 4; 91461190b14Sbellard queue_signal(info.si_signo, &info); 91561190b14Sbellard break; 91661190b14Sbellard case EXCP_DECR: 91761190b14Sbellard /* Should not happen ! */ 91861190b14Sbellard fprintf(stderr, "Decrementer exception\n"); 91961190b14Sbellard if (loglevel) 92061190b14Sbellard fprintf(logfile, "Decrementer exception\n"); 92161190b14Sbellard abort(); 92261190b14Sbellard case EXCP_TRACE: 92361190b14Sbellard /* Do nothing: we use this to trace execution */ 92461190b14Sbellard break; 92561190b14Sbellard case EXCP_FP_ASSIST: 92661190b14Sbellard /* Should not happen ! */ 92761190b14Sbellard fprintf(stderr, "Floating point assist exception\n"); 92861190b14Sbellard if (loglevel) 92961190b14Sbellard fprintf(logfile, "Floating point assist exception\n"); 93061190b14Sbellard abort(); 93161190b14Sbellard case EXCP_MTMSR: 93261190b14Sbellard /* We reloaded the msr, just go on */ 9339fddaa0cSbellard if (msr_pr == 0) { 93461190b14Sbellard fprintf(stderr, "Tried to go into supervisor mode !\n"); 93561190b14Sbellard if (loglevel) 93661190b14Sbellard fprintf(logfile, "Tried to go into supervisor mode !\n"); 93761190b14Sbellard abort(); 93861190b14Sbellard } 93961190b14Sbellard break; 94061190b14Sbellard case EXCP_BRANCH: 94161190b14Sbellard /* We stopped because of a jump... */ 94261190b14Sbellard break; 94361190b14Sbellard case EXCP_INTERRUPT: 94461190b14Sbellard /* Don't know why this should ever happen... */ 94561190b14Sbellard break; 946a541f297Sbellard case EXCP_DEBUG: 9471fddef4bSbellard { 9481fddef4bSbellard int sig; 9491fddef4bSbellard 9501fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 9511fddef4bSbellard if (sig) 9521fddef4bSbellard { 9531fddef4bSbellard info.si_signo = sig; 9541fddef4bSbellard info.si_errno = 0; 9551fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 9561fddef4bSbellard queue_signal(info.si_signo, &info); 9571fddef4bSbellard } 9581fddef4bSbellard } 959a541f297Sbellard break; 96061190b14Sbellard default: 96161190b14Sbellard fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 96261190b14Sbellard trapnr); 96361190b14Sbellard if (loglevel) { 96461190b14Sbellard fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - " 96561190b14Sbellard "0x%02x - aborting\n", trapnr, env->error_code); 96661190b14Sbellard } 96761190b14Sbellard abort(); 96861190b14Sbellard } 96967867308Sbellard process_pending_signals(env); 97067867308Sbellard } 97167867308Sbellard } 97267867308Sbellard #endif 97367867308Sbellard 97431e31b8aSbellard void usage(void) 97531e31b8aSbellard { 9764606bb3fSbellard printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" 9771fddef4bSbellard "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n" 978b346ff46Sbellard "Linux CPU emulator (compiled for %s emulation)\n" 979d691f669Sbellard "\n" 980d691f669Sbellard "-h print this help\n" 9811fddef4bSbellard "-g wait gdb connection to port %d\n" 982b346ff46Sbellard "-L path set the elf interpreter prefix (default=%s)\n" 983b346ff46Sbellard "-s size set the stack size in bytes (default=%ld)\n" 98454936004Sbellard "\n" 98554936004Sbellard "debug options:\n" 986c6981055Sbellard #ifdef USE_CODE_COPY 987c6981055Sbellard "-no-code-copy disable code copy acceleration\n" 988c6981055Sbellard #endif 9896f1f31c0Sbellard "-d options activate log (logfile=%s)\n" 99054936004Sbellard "-p pagesize set the host page size to 'pagesize'\n", 991b346ff46Sbellard TARGET_ARCH, 9921fddef4bSbellard DEFAULT_GDBSTUB_PORT, 993d691f669Sbellard interp_prefix, 99454936004Sbellard x86_stack_size, 99554936004Sbellard DEBUG_LOGFILE); 99674cd30b8Sbellard _exit(1); 99731e31b8aSbellard } 99831e31b8aSbellard 9999de5e440Sbellard /* XXX: currently only used for async signals (see signal.c) */ 1000b346ff46Sbellard CPUState *global_env; 100159faf6d6Sbellard /* used only if single thread */ 100259faf6d6Sbellard CPUState *cpu_single_env = NULL; 100359faf6d6Sbellard 1004851e67a1Sbellard /* used to free thread contexts */ 1005851e67a1Sbellard TaskState *first_task_state; 10069de5e440Sbellard 100731e31b8aSbellard int main(int argc, char **argv) 100831e31b8aSbellard { 100931e31b8aSbellard const char *filename; 101001ffc75bSbellard struct target_pt_regs regs1, *regs = ®s1; 101131e31b8aSbellard struct image_info info1, *info = &info1; 1012851e67a1Sbellard TaskState ts1, *ts = &ts1; 1013b346ff46Sbellard CPUState *env; 1014586314f2Sbellard int optind; 1015d691f669Sbellard const char *r; 10161fddef4bSbellard int use_gdbstub = 0; 101731e31b8aSbellard 101831e31b8aSbellard if (argc <= 1) 101931e31b8aSbellard usage(); 1020f801f97eSbellard 1021cc38b844Sbellard /* init debug */ 1022cc38b844Sbellard cpu_set_log_filename(DEBUG_LOGFILE); 1023cc38b844Sbellard 1024586314f2Sbellard optind = 1; 1025d691f669Sbellard for(;;) { 1026d691f669Sbellard if (optind >= argc) 1027d691f669Sbellard break; 1028d691f669Sbellard r = argv[optind]; 1029d691f669Sbellard if (r[0] != '-') 1030d691f669Sbellard break; 1031586314f2Sbellard optind++; 1032d691f669Sbellard r++; 1033d691f669Sbellard if (!strcmp(r, "-")) { 1034d691f669Sbellard break; 1035d691f669Sbellard } else if (!strcmp(r, "d")) { 1036e19e89a5Sbellard int mask; 1037e19e89a5Sbellard CPULogItem *item; 1038e19e89a5Sbellard 10396f1f31c0Sbellard if (optind >= argc) 10406f1f31c0Sbellard break; 10416f1f31c0Sbellard 10426f1f31c0Sbellard r = argv[optind++]; 10436f1f31c0Sbellard mask = cpu_str_to_log_mask(r); 1044e19e89a5Sbellard if (!mask) { 1045e19e89a5Sbellard printf("Log items (comma separated):\n"); 1046e19e89a5Sbellard for(item = cpu_log_items; item->mask != 0; item++) { 1047e19e89a5Sbellard printf("%-10s %s\n", item->name, item->help); 1048e19e89a5Sbellard } 1049e19e89a5Sbellard exit(1); 1050e19e89a5Sbellard } 1051e19e89a5Sbellard cpu_set_log(mask); 1052d691f669Sbellard } else if (!strcmp(r, "s")) { 1053d691f669Sbellard r = argv[optind++]; 1054d691f669Sbellard x86_stack_size = strtol(r, (char **)&r, 0); 1055d691f669Sbellard if (x86_stack_size <= 0) 1056d691f669Sbellard usage(); 1057d691f669Sbellard if (*r == 'M') 1058d691f669Sbellard x86_stack_size *= 1024 * 1024; 1059d691f669Sbellard else if (*r == 'k' || *r == 'K') 1060d691f669Sbellard x86_stack_size *= 1024; 1061d691f669Sbellard } else if (!strcmp(r, "L")) { 1062d691f669Sbellard interp_prefix = argv[optind++]; 106354936004Sbellard } else if (!strcmp(r, "p")) { 106483fb7adfSbellard qemu_host_page_size = atoi(argv[optind++]); 106583fb7adfSbellard if (qemu_host_page_size == 0 || 106683fb7adfSbellard (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { 106754936004Sbellard fprintf(stderr, "page size must be a power of two\n"); 106854936004Sbellard exit(1); 106954936004Sbellard } 10701fddef4bSbellard } else if (!strcmp(r, "g")) { 10711fddef4bSbellard use_gdbstub = 1; 1072c6981055Sbellard } else 1073c6981055Sbellard #ifdef USE_CODE_COPY 1074c6981055Sbellard if (!strcmp(r, "no-code-copy")) { 1075c6981055Sbellard code_copy_enabled = 0; 1076c6981055Sbellard } else 1077c6981055Sbellard #endif 1078c6981055Sbellard { 1079d691f669Sbellard usage(); 1080586314f2Sbellard } 1081d691f669Sbellard } 1082d691f669Sbellard if (optind >= argc) 1083d691f669Sbellard usage(); 1084586314f2Sbellard filename = argv[optind]; 108531e31b8aSbellard 108631e31b8aSbellard /* Zero out regs */ 108701ffc75bSbellard memset(regs, 0, sizeof(struct target_pt_regs)); 108831e31b8aSbellard 108931e31b8aSbellard /* Zero out image_info */ 109031e31b8aSbellard memset(info, 0, sizeof(struct image_info)); 109131e31b8aSbellard 109274cd30b8Sbellard /* Scan interp_prefix dir for replacement files. */ 109374cd30b8Sbellard init_paths(interp_prefix); 109474cd30b8Sbellard 109583fb7adfSbellard /* NOTE: we need to init the CPU at this stage to get 109683fb7adfSbellard qemu_host_page_size */ 1097b346ff46Sbellard env = cpu_init(); 109854936004Sbellard 109974cd30b8Sbellard if (elf_exec(filename, argv+optind, environ, regs, info) != 0) { 110031e31b8aSbellard printf("Error loading %s\n", filename); 110174cd30b8Sbellard _exit(1); 110231e31b8aSbellard } 110331e31b8aSbellard 11044b74fe1fSbellard if (loglevel) { 110554936004Sbellard page_dump(logfile); 110654936004Sbellard 11074b74fe1fSbellard fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); 11084b74fe1fSbellard fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); 11094b74fe1fSbellard fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); 11104b74fe1fSbellard fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); 11114b74fe1fSbellard fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); 11124b74fe1fSbellard fprintf(logfile, "brk 0x%08lx\n" , info->brk); 1113b346ff46Sbellard fprintf(logfile, "entry 0x%08lx\n" , info->entry); 11144b74fe1fSbellard } 111531e31b8aSbellard 111631e31b8aSbellard target_set_brk((char *)info->brk); 111731e31b8aSbellard syscall_init(); 111866fb9763Sbellard signal_init(); 111931e31b8aSbellard 11209de5e440Sbellard global_env = env; 112131e31b8aSbellard 1122851e67a1Sbellard /* build Task State */ 1123851e67a1Sbellard memset(ts, 0, sizeof(TaskState)); 1124851e67a1Sbellard env->opaque = ts; 1125851e67a1Sbellard ts->used = 1; 112659faf6d6Sbellard env->user_mode_only = 1; 1127851e67a1Sbellard 1128b346ff46Sbellard #if defined(TARGET_I386) 11292e255c6bSbellard cpu_x86_set_cpl(env, 3); 11302e255c6bSbellard 11313802ce26Sbellard env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; 11321bde465eSbellard env->hflags |= HF_PE_MASK; 11331bde465eSbellard if (env->cpuid_features & CPUID_SSE) { 11341bde465eSbellard env->cr[4] |= CR4_OSFXSR_MASK; 11351bde465eSbellard env->hflags |= HF_OSFXSR_MASK; 11361bde465eSbellard } 11373802ce26Sbellard 1138415e561fSbellard /* flags setup : we activate the IRQs by default as in user mode */ 1139415e561fSbellard env->eflags |= IF_MASK; 1140415e561fSbellard 11416dbad63eSbellard /* linux register setup */ 11420ecfa993Sbellard env->regs[R_EAX] = regs->eax; 11430ecfa993Sbellard env->regs[R_EBX] = regs->ebx; 11440ecfa993Sbellard env->regs[R_ECX] = regs->ecx; 11450ecfa993Sbellard env->regs[R_EDX] = regs->edx; 11460ecfa993Sbellard env->regs[R_ESI] = regs->esi; 11470ecfa993Sbellard env->regs[R_EDI] = regs->edi; 11480ecfa993Sbellard env->regs[R_EBP] = regs->ebp; 11490ecfa993Sbellard env->regs[R_ESP] = regs->esp; 1150dab2ed99Sbellard env->eip = regs->eip; 115131e31b8aSbellard 1152f4beb510Sbellard /* linux interrupt setup */ 115380a9d035Sbellard env->idt.base = (long)idt_table; 1154f4beb510Sbellard env->idt.limit = sizeof(idt_table) - 1; 1155f4beb510Sbellard set_idt(0, 0); 1156f4beb510Sbellard set_idt(1, 0); 1157f4beb510Sbellard set_idt(2, 0); 1158f4beb510Sbellard set_idt(3, 3); 1159f4beb510Sbellard set_idt(4, 3); 1160f4beb510Sbellard set_idt(5, 3); 1161f4beb510Sbellard set_idt(6, 0); 1162f4beb510Sbellard set_idt(7, 0); 1163f4beb510Sbellard set_idt(8, 0); 1164f4beb510Sbellard set_idt(9, 0); 1165f4beb510Sbellard set_idt(10, 0); 1166f4beb510Sbellard set_idt(11, 0); 1167f4beb510Sbellard set_idt(12, 0); 1168f4beb510Sbellard set_idt(13, 0); 1169f4beb510Sbellard set_idt(14, 0); 1170f4beb510Sbellard set_idt(15, 0); 1171f4beb510Sbellard set_idt(16, 0); 1172f4beb510Sbellard set_idt(17, 0); 1173f4beb510Sbellard set_idt(18, 0); 1174f4beb510Sbellard set_idt(19, 0); 1175f4beb510Sbellard set_idt(0x80, 3); 1176f4beb510Sbellard 11776dbad63eSbellard /* linux segment setup */ 117880a9d035Sbellard env->gdt.base = (long)gdt_table; 11796dbad63eSbellard env->gdt.limit = sizeof(gdt_table) - 1; 1180f4beb510Sbellard write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 1181f4beb510Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 1182f4beb510Sbellard (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 1183f4beb510Sbellard write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, 1184f4beb510Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 1185f4beb510Sbellard (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); 11866dbad63eSbellard cpu_x86_load_seg(env, R_CS, __USER_CS); 11876dbad63eSbellard cpu_x86_load_seg(env, R_DS, __USER_DS); 11886dbad63eSbellard cpu_x86_load_seg(env, R_ES, __USER_DS); 11896dbad63eSbellard cpu_x86_load_seg(env, R_SS, __USER_DS); 11906dbad63eSbellard cpu_x86_load_seg(env, R_FS, __USER_DS); 11916dbad63eSbellard cpu_x86_load_seg(env, R_GS, __USER_DS); 119292ccca6aSbellard 1193b346ff46Sbellard #elif defined(TARGET_ARM) 1194b346ff46Sbellard { 1195b346ff46Sbellard int i; 1196b346ff46Sbellard for(i = 0; i < 16; i++) { 1197b346ff46Sbellard env->regs[i] = regs->uregs[i]; 1198b346ff46Sbellard } 1199b346ff46Sbellard env->cpsr = regs->uregs[16]; 1200a4f81979Sbellard ts->stack_base = info->start_stack; 1201a4f81979Sbellard ts->heap_base = info->brk; 1202a4f81979Sbellard /* This will be filled in on the first SYS_HEAPINFO call. */ 1203a4f81979Sbellard ts->heap_limit = 0; 1204b346ff46Sbellard } 120593ac68bcSbellard #elif defined(TARGET_SPARC) 1206060366c5Sbellard { 1207060366c5Sbellard int i; 1208060366c5Sbellard env->pc = regs->pc; 1209060366c5Sbellard env->npc = regs->npc; 1210060366c5Sbellard env->y = regs->y; 1211060366c5Sbellard for(i = 0; i < 8; i++) 1212060366c5Sbellard env->gregs[i] = regs->u_regs[i]; 1213060366c5Sbellard for(i = 0; i < 8; i++) 1214060366c5Sbellard env->regwptr[i] = regs->u_regs[i + 8]; 1215060366c5Sbellard } 121667867308Sbellard #elif defined(TARGET_PPC) 121767867308Sbellard { 12183fc6c082Sbellard ppc_def_t *def; 121967867308Sbellard int i; 12203fc6c082Sbellard 12213fc6c082Sbellard /* Choose and initialise CPU */ 12223fc6c082Sbellard /* XXX: CPU model (or PVR) should be provided on command line */ 12233fc6c082Sbellard // ppc_find_by_name("750gx", &def); 12243fc6c082Sbellard // ppc_find_by_name("750fx", &def); 12253fc6c082Sbellard // ppc_find_by_name("750p", &def); 12263fc6c082Sbellard ppc_find_by_name("750", &def); 12273fc6c082Sbellard // ppc_find_by_name("G3", &def); 12283fc6c082Sbellard // ppc_find_by_name("604r", &def); 12293fc6c082Sbellard // ppc_find_by_name("604e", &def); 12303fc6c082Sbellard // ppc_find_by_name("604", &def); 12313fc6c082Sbellard if (def == NULL) { 12323fc6c082Sbellard cpu_abort(cpu_single_env, 12333fc6c082Sbellard "Unable to find PowerPC CPU definition\n"); 12343fc6c082Sbellard } 12353fc6c082Sbellard cpu_ppc_register(cpu_single_env, def); 12363fc6c082Sbellard 123761190b14Sbellard for (i = 0; i < 32; i++) { 12384c2e770fSbellard if (i != 12 && i != 6 && i != 13) 123967867308Sbellard env->msr[i] = (regs->msr >> i) & 1; 124061190b14Sbellard } 124167867308Sbellard env->nip = regs->nip; 124267867308Sbellard for(i = 0; i < 32; i++) { 124367867308Sbellard env->gpr[i] = regs->gpr[i]; 124467867308Sbellard } 124567867308Sbellard } 1246b346ff46Sbellard #else 1247b346ff46Sbellard #error unsupported target CPU 1248b346ff46Sbellard #endif 124931e31b8aSbellard 12501fddef4bSbellard if (use_gdbstub) { 12511fddef4bSbellard gdbserver_start (DEFAULT_GDBSTUB_PORT); 12521fddef4bSbellard gdb_handlesig(env, 0); 12531fddef4bSbellard } 12541b6b029eSbellard cpu_loop(env); 12551b6b029eSbellard /* never exits */ 125631e31b8aSbellard return 0; 125731e31b8aSbellard } 1258