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