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" 36d8fd2954SPaul Brook #include "elf.h" 3704a6dfebSaurel32 383ef693a0Sbellard #define DEBUG_LOGFILE "/tmp/qemu.log" 39586314f2Sbellard 40d088d664Saurel32 char *exec_path; 41d088d664Saurel32 421b530a6dSaurel32 int singlestep; 43fc9c5412SJohannes Schauer const char *filename; 44fc9c5412SJohannes Schauer const char *argv0; 45fc9c5412SJohannes Schauer int gdbstub_port; 46fc9c5412SJohannes Schauer envlist_t *envlist; 47fc9c5412SJohannes Schauer const char *cpu_model; 48379f6698SPaul Brook unsigned long mmap_min_addr; 4914f24e14SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE) 50379f6698SPaul Brook unsigned long guest_base; 51379f6698SPaul Brook int have_guest_base; 52288e65b9SAlexander Graf #if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64) 53288e65b9SAlexander Graf /* 54288e65b9SAlexander Graf * When running 32-on-64 we should make sure we can fit all of the possible 55288e65b9SAlexander Graf * guest address space into a contiguous chunk of virtual host memory. 56288e65b9SAlexander Graf * 57288e65b9SAlexander Graf * This way we will never overlap with our own libraries or binaries or stack 58288e65b9SAlexander Graf * or anything else that QEMU maps. 59288e65b9SAlexander Graf */ 60288e65b9SAlexander Graf unsigned long reserved_va = 0xf7000000; 61288e65b9SAlexander Graf #else 6268a1c816SPaul Brook unsigned long reserved_va; 63379f6698SPaul Brook #endif 64288e65b9SAlexander Graf #endif 651b530a6dSaurel32 66fc9c5412SJohannes Schauer static void usage(void); 67fc9c5412SJohannes Schauer 687ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; 69c5937220Spbrook const char *qemu_uname_release = CONFIG_UNAME_RELEASE; 70586314f2Sbellard 719de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so 729de5e440Sbellard we allocate a bigger stack. Need a better solution, for example 739de5e440Sbellard by remapping the process stack directly at the right place */ 74703e0e89SRichard Henderson unsigned long guest_stack_size = 8 * 1024 * 1024UL; 7531e31b8aSbellard 7631e31b8aSbellard void gemu_log(const char *fmt, ...) 7731e31b8aSbellard { 7831e31b8aSbellard va_list ap; 7931e31b8aSbellard 8031e31b8aSbellard va_start(ap, fmt); 8131e31b8aSbellard vfprintf(stderr, fmt, ap); 8231e31b8aSbellard va_end(ap); 8331e31b8aSbellard } 8431e31b8aSbellard 858fcd3692Sblueswir1 #if defined(TARGET_I386) 8605390248SAndreas Färber int cpu_get_pic_interrupt(CPUX86State *env) 8792ccca6aSbellard { 8892ccca6aSbellard return -1; 8992ccca6aSbellard } 908fcd3692Sblueswir1 #endif 9192ccca6aSbellard 922f7bb878SJuan Quintela #if defined(CONFIG_USE_NPTL) 93d5975363Spbrook /***********************************************************/ 94d5975363Spbrook /* Helper routines for implementing atomic operations. */ 95d5975363Spbrook 96d5975363Spbrook /* To implement exclusive operations we force all cpus to syncronise. 97d5975363Spbrook We don't require a full sync, only that no cpus are executing guest code. 98d5975363Spbrook The alternative is to map target atomic ops onto host equivalents, 99d5975363Spbrook which requires quite a lot of per host/target work. */ 100c2764719Spbrook static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER; 101d5975363Spbrook static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER; 102d5975363Spbrook static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER; 103d5975363Spbrook static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER; 104d5975363Spbrook static int pending_cpus; 105d5975363Spbrook 106d5975363Spbrook /* Make sure everything is in a consistent state for calling fork(). */ 107d5975363Spbrook void fork_start(void) 108d5975363Spbrook { 109d5975363Spbrook pthread_mutex_lock(&tb_lock); 110d5975363Spbrook pthread_mutex_lock(&exclusive_lock); 111d032d1b4SRiku Voipio mmap_fork_start(); 112d5975363Spbrook } 113d5975363Spbrook 114d5975363Spbrook void fork_end(int child) 115d5975363Spbrook { 116d032d1b4SRiku Voipio mmap_fork_end(child); 117d5975363Spbrook if (child) { 118d5975363Spbrook /* Child processes created by fork() only have a single thread. 119d5975363Spbrook Discard information about the parent threads. */ 120d5975363Spbrook first_cpu = thread_env; 121d5975363Spbrook thread_env->next_cpu = NULL; 122d5975363Spbrook pending_cpus = 0; 123d5975363Spbrook pthread_mutex_init(&exclusive_lock, NULL); 124c2764719Spbrook pthread_mutex_init(&cpu_list_mutex, NULL); 125d5975363Spbrook pthread_cond_init(&exclusive_cond, NULL); 126d5975363Spbrook pthread_cond_init(&exclusive_resume, NULL); 127d5975363Spbrook pthread_mutex_init(&tb_lock, NULL); 1282b1319c8Saurel32 gdbserver_fork(thread_env); 129d5975363Spbrook } else { 130d5975363Spbrook pthread_mutex_unlock(&exclusive_lock); 131d5975363Spbrook pthread_mutex_unlock(&tb_lock); 132d5975363Spbrook } 133d5975363Spbrook } 134d5975363Spbrook 135d5975363Spbrook /* Wait for pending exclusive operations to complete. The exclusive lock 136d5975363Spbrook must be held. */ 137d5975363Spbrook static inline void exclusive_idle(void) 138d5975363Spbrook { 139d5975363Spbrook while (pending_cpus) { 140d5975363Spbrook pthread_cond_wait(&exclusive_resume, &exclusive_lock); 141d5975363Spbrook } 142d5975363Spbrook } 143d5975363Spbrook 144d5975363Spbrook /* Start an exclusive operation. 145d5975363Spbrook Must only be called from outside cpu_arm_exec. */ 146d5975363Spbrook static inline void start_exclusive(void) 147d5975363Spbrook { 1489349b4f9SAndreas Färber CPUArchState *other; 149d5975363Spbrook pthread_mutex_lock(&exclusive_lock); 150d5975363Spbrook exclusive_idle(); 151d5975363Spbrook 152d5975363Spbrook pending_cpus = 1; 153d5975363Spbrook /* Make all other cpus stop executing. */ 154d5975363Spbrook for (other = first_cpu; other; other = other->next_cpu) { 155d5975363Spbrook if (other->running) { 156d5975363Spbrook pending_cpus++; 1573098dba0Saurel32 cpu_exit(other); 158d5975363Spbrook } 159d5975363Spbrook } 160d5975363Spbrook if (pending_cpus > 1) { 161d5975363Spbrook pthread_cond_wait(&exclusive_cond, &exclusive_lock); 162d5975363Spbrook } 163d5975363Spbrook } 164d5975363Spbrook 165d5975363Spbrook /* Finish an exclusive operation. */ 166d5975363Spbrook static inline void end_exclusive(void) 167d5975363Spbrook { 168d5975363Spbrook pending_cpus = 0; 169d5975363Spbrook pthread_cond_broadcast(&exclusive_resume); 170d5975363Spbrook pthread_mutex_unlock(&exclusive_lock); 171d5975363Spbrook } 172d5975363Spbrook 173d5975363Spbrook /* Wait for exclusive ops to finish, and begin cpu execution. */ 1749349b4f9SAndreas Färber static inline void cpu_exec_start(CPUArchState *env) 175d5975363Spbrook { 176d5975363Spbrook pthread_mutex_lock(&exclusive_lock); 177d5975363Spbrook exclusive_idle(); 178d5975363Spbrook env->running = 1; 179d5975363Spbrook pthread_mutex_unlock(&exclusive_lock); 180d5975363Spbrook } 181d5975363Spbrook 182d5975363Spbrook /* Mark cpu as not executing, and release pending exclusive ops. */ 1839349b4f9SAndreas Färber static inline void cpu_exec_end(CPUArchState *env) 184d5975363Spbrook { 185d5975363Spbrook pthread_mutex_lock(&exclusive_lock); 186d5975363Spbrook env->running = 0; 187d5975363Spbrook if (pending_cpus > 1) { 188d5975363Spbrook pending_cpus--; 189d5975363Spbrook if (pending_cpus == 1) { 190d5975363Spbrook pthread_cond_signal(&exclusive_cond); 191d5975363Spbrook } 192d5975363Spbrook } 193d5975363Spbrook exclusive_idle(); 194d5975363Spbrook pthread_mutex_unlock(&exclusive_lock); 195d5975363Spbrook } 196c2764719Spbrook 197c2764719Spbrook void cpu_list_lock(void) 198c2764719Spbrook { 199c2764719Spbrook pthread_mutex_lock(&cpu_list_mutex); 200c2764719Spbrook } 201c2764719Spbrook 202c2764719Spbrook void cpu_list_unlock(void) 203c2764719Spbrook { 204c2764719Spbrook pthread_mutex_unlock(&cpu_list_mutex); 205c2764719Spbrook } 2062f7bb878SJuan Quintela #else /* if !CONFIG_USE_NPTL */ 207d5975363Spbrook /* These are no-ops because we are not threadsafe. */ 2089349b4f9SAndreas Färber static inline void cpu_exec_start(CPUArchState *env) 209d5975363Spbrook { 210d5975363Spbrook } 211d5975363Spbrook 2129349b4f9SAndreas Färber static inline void cpu_exec_end(CPUArchState *env) 213d5975363Spbrook { 214d5975363Spbrook } 215d5975363Spbrook 216d5975363Spbrook static inline void start_exclusive(void) 217d5975363Spbrook { 218d5975363Spbrook } 219d5975363Spbrook 220d5975363Spbrook static inline void end_exclusive(void) 221d5975363Spbrook { 222d5975363Spbrook } 223d5975363Spbrook 224d5975363Spbrook void fork_start(void) 225d5975363Spbrook { 226d5975363Spbrook } 227d5975363Spbrook 228d5975363Spbrook void fork_end(int child) 229d5975363Spbrook { 2302b1319c8Saurel32 if (child) { 2312b1319c8Saurel32 gdbserver_fork(thread_env); 2322b1319c8Saurel32 } 233d5975363Spbrook } 234c2764719Spbrook 235c2764719Spbrook void cpu_list_lock(void) 236c2764719Spbrook { 237c2764719Spbrook } 238c2764719Spbrook 239c2764719Spbrook void cpu_list_unlock(void) 240c2764719Spbrook { 241c2764719Spbrook } 242d5975363Spbrook #endif 243d5975363Spbrook 244d5975363Spbrook 245a541f297Sbellard #ifdef TARGET_I386 246a541f297Sbellard /***********************************************************/ 247a541f297Sbellard /* CPUX86 core interface */ 248a541f297Sbellard 24905390248SAndreas Färber void cpu_smm_update(CPUX86State *env) 25002a1602eSbellard { 25102a1602eSbellard } 25202a1602eSbellard 25328ab0e2eSbellard uint64_t cpu_get_tsc(CPUX86State *env) 25428ab0e2eSbellard { 25528ab0e2eSbellard return cpu_get_real_ticks(); 25628ab0e2eSbellard } 25728ab0e2eSbellard 258f4beb510Sbellard static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 259f4beb510Sbellard int flags) 2606dbad63eSbellard { 261f4beb510Sbellard unsigned int e1, e2; 26253a5960aSpbrook uint32_t *p; 2636dbad63eSbellard e1 = (addr << 16) | (limit & 0xffff); 2646dbad63eSbellard e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); 265f4beb510Sbellard e2 |= flags; 26653a5960aSpbrook p = ptr; 267d538e8f5Smalc p[0] = tswap32(e1); 268d538e8f5Smalc p[1] = tswap32(e2); 269f4beb510Sbellard } 270f4beb510Sbellard 271e441570fSbalrog static uint64_t *idt_table; 272eb38c52cSblueswir1 #ifdef TARGET_X86_64 273d2fd1af7Sbellard static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, 274d2fd1af7Sbellard uint64_t addr, unsigned int sel) 275d2fd1af7Sbellard { 2764dbc422bSbellard uint32_t *p, e1, e2; 277d2fd1af7Sbellard e1 = (addr & 0xffff) | (sel << 16); 278d2fd1af7Sbellard e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 279d2fd1af7Sbellard p = ptr; 2804dbc422bSbellard p[0] = tswap32(e1); 2814dbc422bSbellard p[1] = tswap32(e2); 2824dbc422bSbellard p[2] = tswap32(addr >> 32); 2834dbc422bSbellard p[3] = 0; 284d2fd1af7Sbellard } 285d2fd1af7Sbellard /* only dpl matters as we do only user space emulation */ 286d2fd1af7Sbellard static void set_idt(int n, unsigned int dpl) 287d2fd1af7Sbellard { 288d2fd1af7Sbellard set_gate64(idt_table + n * 2, 0, dpl, 0, 0); 289d2fd1af7Sbellard } 290d2fd1af7Sbellard #else 291f4beb510Sbellard static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 292d2fd1af7Sbellard uint32_t addr, unsigned int sel) 293f4beb510Sbellard { 2944dbc422bSbellard uint32_t *p, e1, e2; 295f4beb510Sbellard e1 = (addr & 0xffff) | (sel << 16); 296f4beb510Sbellard e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 29753a5960aSpbrook p = ptr; 2984dbc422bSbellard p[0] = tswap32(e1); 2994dbc422bSbellard p[1] = tswap32(e2); 3006dbad63eSbellard } 3016dbad63eSbellard 302f4beb510Sbellard /* only dpl matters as we do only user space emulation */ 303f4beb510Sbellard static void set_idt(int n, unsigned int dpl) 304f4beb510Sbellard { 305f4beb510Sbellard set_gate(idt_table + n, 0, dpl, 0, 0); 306f4beb510Sbellard } 307d2fd1af7Sbellard #endif 30831e31b8aSbellard 30989e957e7Sbellard void cpu_loop(CPUX86State *env) 310bc8a22ccSbellard { 311bc8a22ccSbellard int trapnr; 312992f48a0Sblueswir1 abi_ulong pc; 313c227f099SAnthony Liguori target_siginfo_t info; 314bc8a22ccSbellard 315bc8a22ccSbellard for(;;) { 316bc8a22ccSbellard trapnr = cpu_x86_exec(env); 317bc8a22ccSbellard switch(trapnr) { 318f4beb510Sbellard case 0x80: 319d2fd1af7Sbellard /* linux syscall from int $0x80 */ 3201b6b029eSbellard env->regs[R_EAX] = do_syscall(env, 3211b6b029eSbellard env->regs[R_EAX], 3221b6b029eSbellard env->regs[R_EBX], 3231b6b029eSbellard env->regs[R_ECX], 3241b6b029eSbellard env->regs[R_EDX], 3251b6b029eSbellard env->regs[R_ESI], 3261b6b029eSbellard env->regs[R_EDI], 3275945cfcbSPeter Maydell env->regs[R_EBP], 3285945cfcbSPeter Maydell 0, 0); 329f4beb510Sbellard break; 330d2fd1af7Sbellard #ifndef TARGET_ABI32 331d2fd1af7Sbellard case EXCP_SYSCALL: 3325ba18547SStefan Weil /* linux syscall from syscall instruction */ 333d2fd1af7Sbellard env->regs[R_EAX] = do_syscall(env, 334d2fd1af7Sbellard env->regs[R_EAX], 335d2fd1af7Sbellard env->regs[R_EDI], 336d2fd1af7Sbellard env->regs[R_ESI], 337d2fd1af7Sbellard env->regs[R_EDX], 338d2fd1af7Sbellard env->regs[10], 339d2fd1af7Sbellard env->regs[8], 3405945cfcbSPeter Maydell env->regs[9], 3415945cfcbSPeter Maydell 0, 0); 342d2fd1af7Sbellard env->eip = env->exception_next_eip; 343d2fd1af7Sbellard break; 344d2fd1af7Sbellard #endif 345f4beb510Sbellard case EXCP0B_NOSEG: 346f4beb510Sbellard case EXCP0C_STACK: 347f4beb510Sbellard info.si_signo = SIGBUS; 348f4beb510Sbellard info.si_errno = 0; 349f4beb510Sbellard info.si_code = TARGET_SI_KERNEL; 350f4beb510Sbellard info._sifields._sigfault._addr = 0; 351624f7979Spbrook queue_signal(env, info.si_signo, &info); 352f4beb510Sbellard break; 353f4beb510Sbellard case EXCP0D_GPF: 354d2fd1af7Sbellard /* XXX: potential problem if ABI32 */ 35584409ddbSj_mayer #ifndef TARGET_X86_64 356f4beb510Sbellard if (env->eflags & VM_MASK) { 357f4beb510Sbellard handle_vm86_fault(env); 35884409ddbSj_mayer } else 35984409ddbSj_mayer #endif 36084409ddbSj_mayer { 3619de5e440Sbellard info.si_signo = SIGSEGV; 3629de5e440Sbellard info.si_errno = 0; 363b689bc57Sbellard info.si_code = TARGET_SI_KERNEL; 3649de5e440Sbellard info._sifields._sigfault._addr = 0; 365624f7979Spbrook queue_signal(env, info.si_signo, &info); 3661b6b029eSbellard } 3671b6b029eSbellard break; 368b689bc57Sbellard case EXCP0E_PAGE: 369b689bc57Sbellard info.si_signo = SIGSEGV; 370b689bc57Sbellard info.si_errno = 0; 371b689bc57Sbellard if (!(env->error_code & 1)) 372b689bc57Sbellard info.si_code = TARGET_SEGV_MAPERR; 373b689bc57Sbellard else 374b689bc57Sbellard info.si_code = TARGET_SEGV_ACCERR; 375970a87a6Sbellard info._sifields._sigfault._addr = env->cr[2]; 376624f7979Spbrook queue_signal(env, info.si_signo, &info); 377b689bc57Sbellard break; 3789de5e440Sbellard case EXCP00_DIVZ: 37984409ddbSj_mayer #ifndef TARGET_X86_64 380bc8a22ccSbellard if (env->eflags & VM_MASK) { 381447db213Sbellard handle_vm86_trap(env, trapnr); 38284409ddbSj_mayer } else 38384409ddbSj_mayer #endif 38484409ddbSj_mayer { 3859de5e440Sbellard /* division by zero */ 3869de5e440Sbellard info.si_signo = SIGFPE; 3879de5e440Sbellard info.si_errno = 0; 3889de5e440Sbellard info.si_code = TARGET_FPE_INTDIV; 3899de5e440Sbellard info._sifields._sigfault._addr = env->eip; 390624f7979Spbrook queue_signal(env, info.si_signo, &info); 391bc8a22ccSbellard } 3929de5e440Sbellard break; 39301df040bSaliguori case EXCP01_DB: 394447db213Sbellard case EXCP03_INT3: 39584409ddbSj_mayer #ifndef TARGET_X86_64 396447db213Sbellard if (env->eflags & VM_MASK) { 397447db213Sbellard handle_vm86_trap(env, trapnr); 39884409ddbSj_mayer } else 39984409ddbSj_mayer #endif 40084409ddbSj_mayer { 401447db213Sbellard info.si_signo = SIGTRAP; 402447db213Sbellard info.si_errno = 0; 40301df040bSaliguori if (trapnr == EXCP01_DB) { 404447db213Sbellard info.si_code = TARGET_TRAP_BRKPT; 405447db213Sbellard info._sifields._sigfault._addr = env->eip; 406447db213Sbellard } else { 407447db213Sbellard info.si_code = TARGET_SI_KERNEL; 408447db213Sbellard info._sifields._sigfault._addr = 0; 409447db213Sbellard } 410624f7979Spbrook queue_signal(env, info.si_signo, &info); 411447db213Sbellard } 412447db213Sbellard break; 4139de5e440Sbellard case EXCP04_INTO: 4149de5e440Sbellard case EXCP05_BOUND: 41584409ddbSj_mayer #ifndef TARGET_X86_64 416bc8a22ccSbellard if (env->eflags & VM_MASK) { 417447db213Sbellard handle_vm86_trap(env, trapnr); 41884409ddbSj_mayer } else 41984409ddbSj_mayer #endif 42084409ddbSj_mayer { 4219de5e440Sbellard info.si_signo = SIGSEGV; 4229de5e440Sbellard info.si_errno = 0; 423b689bc57Sbellard info.si_code = TARGET_SI_KERNEL; 4249de5e440Sbellard info._sifields._sigfault._addr = 0; 425624f7979Spbrook queue_signal(env, info.si_signo, &info); 426bc8a22ccSbellard } 4279de5e440Sbellard break; 4289de5e440Sbellard case EXCP06_ILLOP: 4299de5e440Sbellard info.si_signo = SIGILL; 4309de5e440Sbellard info.si_errno = 0; 4319de5e440Sbellard info.si_code = TARGET_ILL_ILLOPN; 4329de5e440Sbellard info._sifields._sigfault._addr = env->eip; 433624f7979Spbrook queue_signal(env, info.si_signo, &info); 4349de5e440Sbellard break; 4359de5e440Sbellard case EXCP_INTERRUPT: 4369de5e440Sbellard /* just indicate that signals should be handled asap */ 4379de5e440Sbellard break; 4381fddef4bSbellard case EXCP_DEBUG: 4391fddef4bSbellard { 4401fddef4bSbellard int sig; 4411fddef4bSbellard 4421fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 4431fddef4bSbellard if (sig) 4441fddef4bSbellard { 4451fddef4bSbellard info.si_signo = sig; 4461fddef4bSbellard info.si_errno = 0; 4471fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 448624f7979Spbrook queue_signal(env, info.si_signo, &info); 4491fddef4bSbellard } 4501fddef4bSbellard } 4511fddef4bSbellard break; 4521b6b029eSbellard default: 453970a87a6Sbellard pc = env->segs[R_CS].base + env->eip; 454bc8a22ccSbellard fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 455bc8a22ccSbellard (long)pc, trapnr); 4561b6b029eSbellard abort(); 4571b6b029eSbellard } 45866fb9763Sbellard process_pending_signals(env); 4591b6b029eSbellard } 4601b6b029eSbellard } 461b346ff46Sbellard #endif 462b346ff46Sbellard 463b346ff46Sbellard #ifdef TARGET_ARM 464b346ff46Sbellard 465d8fd2954SPaul Brook #define get_user_code_u32(x, gaddr, doswap) \ 466d8fd2954SPaul Brook ({ abi_long __r = get_user_u32((x), (gaddr)); \ 467d8fd2954SPaul Brook if (!__r && (doswap)) { \ 468d8fd2954SPaul Brook (x) = bswap32(x); \ 469d8fd2954SPaul Brook } \ 470d8fd2954SPaul Brook __r; \ 471d8fd2954SPaul Brook }) 472d8fd2954SPaul Brook 473d8fd2954SPaul Brook #define get_user_code_u16(x, gaddr, doswap) \ 474d8fd2954SPaul Brook ({ abi_long __r = get_user_u16((x), (gaddr)); \ 475d8fd2954SPaul Brook if (!__r && (doswap)) { \ 476d8fd2954SPaul Brook (x) = bswap16(x); \ 477d8fd2954SPaul Brook } \ 478d8fd2954SPaul Brook __r; \ 479d8fd2954SPaul Brook }) 480d8fd2954SPaul Brook 48197cc7560SDr. David Alan Gilbert /* 48297cc7560SDr. David Alan Gilbert * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt 48397cc7560SDr. David Alan Gilbert * Input: 48497cc7560SDr. David Alan Gilbert * r0 = pointer to oldval 48597cc7560SDr. David Alan Gilbert * r1 = pointer to newval 48697cc7560SDr. David Alan Gilbert * r2 = pointer to target value 48797cc7560SDr. David Alan Gilbert * 48897cc7560SDr. David Alan Gilbert * Output: 48997cc7560SDr. David Alan Gilbert * r0 = 0 if *ptr was changed, non-0 if no exchange happened 49097cc7560SDr. David Alan Gilbert * C set if *ptr was changed, clear if no exchange happened 49197cc7560SDr. David Alan Gilbert * 49297cc7560SDr. David Alan Gilbert * Note segv's in kernel helpers are a bit tricky, we can set the 49397cc7560SDr. David Alan Gilbert * data address sensibly but the PC address is just the entry point. 49497cc7560SDr. David Alan Gilbert */ 49597cc7560SDr. David Alan Gilbert static void arm_kernel_cmpxchg64_helper(CPUARMState *env) 49697cc7560SDr. David Alan Gilbert { 49797cc7560SDr. David Alan Gilbert uint64_t oldval, newval, val; 49897cc7560SDr. David Alan Gilbert uint32_t addr, cpsr; 49997cc7560SDr. David Alan Gilbert target_siginfo_t info; 50097cc7560SDr. David Alan Gilbert 50197cc7560SDr. David Alan Gilbert /* Based on the 32 bit code in do_kernel_trap */ 50297cc7560SDr. David Alan Gilbert 50397cc7560SDr. David Alan Gilbert /* XXX: This only works between threads, not between processes. 50497cc7560SDr. David Alan Gilbert It's probably possible to implement this with native host 50597cc7560SDr. David Alan Gilbert operations. However things like ldrex/strex are much harder so 50697cc7560SDr. David Alan Gilbert there's not much point trying. */ 50797cc7560SDr. David Alan Gilbert start_exclusive(); 50897cc7560SDr. David Alan Gilbert cpsr = cpsr_read(env); 50997cc7560SDr. David Alan Gilbert addr = env->regs[2]; 51097cc7560SDr. David Alan Gilbert 51197cc7560SDr. David Alan Gilbert if (get_user_u64(oldval, env->regs[0])) { 51297cc7560SDr. David Alan Gilbert env->cp15.c6_data = env->regs[0]; 51397cc7560SDr. David Alan Gilbert goto segv; 51497cc7560SDr. David Alan Gilbert }; 51597cc7560SDr. David Alan Gilbert 51697cc7560SDr. David Alan Gilbert if (get_user_u64(newval, env->regs[1])) { 51797cc7560SDr. David Alan Gilbert env->cp15.c6_data = env->regs[1]; 51897cc7560SDr. David Alan Gilbert goto segv; 51997cc7560SDr. David Alan Gilbert }; 52097cc7560SDr. David Alan Gilbert 52197cc7560SDr. David Alan Gilbert if (get_user_u64(val, addr)) { 52297cc7560SDr. David Alan Gilbert env->cp15.c6_data = addr; 52397cc7560SDr. David Alan Gilbert goto segv; 52497cc7560SDr. David Alan Gilbert } 52597cc7560SDr. David Alan Gilbert 52697cc7560SDr. David Alan Gilbert if (val == oldval) { 52797cc7560SDr. David Alan Gilbert val = newval; 52897cc7560SDr. David Alan Gilbert 52997cc7560SDr. David Alan Gilbert if (put_user_u64(val, addr)) { 53097cc7560SDr. David Alan Gilbert env->cp15.c6_data = addr; 53197cc7560SDr. David Alan Gilbert goto segv; 53297cc7560SDr. David Alan Gilbert }; 53397cc7560SDr. David Alan Gilbert 53497cc7560SDr. David Alan Gilbert env->regs[0] = 0; 53597cc7560SDr. David Alan Gilbert cpsr |= CPSR_C; 53697cc7560SDr. David Alan Gilbert } else { 53797cc7560SDr. David Alan Gilbert env->regs[0] = -1; 53897cc7560SDr. David Alan Gilbert cpsr &= ~CPSR_C; 53997cc7560SDr. David Alan Gilbert } 54097cc7560SDr. David Alan Gilbert cpsr_write(env, cpsr, CPSR_C); 54197cc7560SDr. David Alan Gilbert end_exclusive(); 54297cc7560SDr. David Alan Gilbert return; 54397cc7560SDr. David Alan Gilbert 54497cc7560SDr. David Alan Gilbert segv: 54597cc7560SDr. David Alan Gilbert end_exclusive(); 54697cc7560SDr. David Alan Gilbert /* We get the PC of the entry address - which is as good as anything, 54797cc7560SDr. David Alan Gilbert on a real kernel what you get depends on which mode it uses. */ 54897cc7560SDr. David Alan Gilbert info.si_signo = SIGSEGV; 54997cc7560SDr. David Alan Gilbert info.si_errno = 0; 55097cc7560SDr. David Alan Gilbert /* XXX: check env->error_code */ 55197cc7560SDr. David Alan Gilbert info.si_code = TARGET_SEGV_MAPERR; 55297cc7560SDr. David Alan Gilbert info._sifields._sigfault._addr = env->cp15.c6_data; 55397cc7560SDr. David Alan Gilbert queue_signal(env, info.si_signo, &info); 55497cc7560SDr. David Alan Gilbert 55597cc7560SDr. David Alan Gilbert end_exclusive(); 55697cc7560SDr. David Alan Gilbert } 55797cc7560SDr. David Alan Gilbert 558fbb4a2e3Spbrook /* Handle a jump to the kernel code page. */ 559fbb4a2e3Spbrook static int 560fbb4a2e3Spbrook do_kernel_trap(CPUARMState *env) 561fbb4a2e3Spbrook { 562fbb4a2e3Spbrook uint32_t addr; 563fbb4a2e3Spbrook uint32_t cpsr; 564fbb4a2e3Spbrook uint32_t val; 565fbb4a2e3Spbrook 566fbb4a2e3Spbrook switch (env->regs[15]) { 567fbb4a2e3Spbrook case 0xffff0fa0: /* __kernel_memory_barrier */ 568fbb4a2e3Spbrook /* ??? No-op. Will need to do better for SMP. */ 569fbb4a2e3Spbrook break; 570fbb4a2e3Spbrook case 0xffff0fc0: /* __kernel_cmpxchg */ 571d5975363Spbrook /* XXX: This only works between threads, not between processes. 572d5975363Spbrook It's probably possible to implement this with native host 573d5975363Spbrook operations. However things like ldrex/strex are much harder so 574d5975363Spbrook there's not much point trying. */ 575d5975363Spbrook start_exclusive(); 576fbb4a2e3Spbrook cpsr = cpsr_read(env); 577fbb4a2e3Spbrook addr = env->regs[2]; 578fbb4a2e3Spbrook /* FIXME: This should SEGV if the access fails. */ 579fbb4a2e3Spbrook if (get_user_u32(val, addr)) 580fbb4a2e3Spbrook val = ~env->regs[0]; 581fbb4a2e3Spbrook if (val == env->regs[0]) { 582fbb4a2e3Spbrook val = env->regs[1]; 583fbb4a2e3Spbrook /* FIXME: Check for segfaults. */ 584fbb4a2e3Spbrook put_user_u32(val, addr); 585fbb4a2e3Spbrook env->regs[0] = 0; 586fbb4a2e3Spbrook cpsr |= CPSR_C; 587fbb4a2e3Spbrook } else { 588fbb4a2e3Spbrook env->regs[0] = -1; 589fbb4a2e3Spbrook cpsr &= ~CPSR_C; 590fbb4a2e3Spbrook } 591fbb4a2e3Spbrook cpsr_write(env, cpsr, CPSR_C); 592d5975363Spbrook end_exclusive(); 593fbb4a2e3Spbrook break; 594fbb4a2e3Spbrook case 0xffff0fe0: /* __kernel_get_tls */ 595fbb4a2e3Spbrook env->regs[0] = env->cp15.c13_tls2; 596fbb4a2e3Spbrook break; 59797cc7560SDr. David Alan Gilbert case 0xffff0f60: /* __kernel_cmpxchg64 */ 59897cc7560SDr. David Alan Gilbert arm_kernel_cmpxchg64_helper(env); 59997cc7560SDr. David Alan Gilbert break; 60097cc7560SDr. David Alan Gilbert 601fbb4a2e3Spbrook default: 602fbb4a2e3Spbrook return 1; 603fbb4a2e3Spbrook } 604fbb4a2e3Spbrook /* Jump back to the caller. */ 605fbb4a2e3Spbrook addr = env->regs[14]; 606fbb4a2e3Spbrook if (addr & 1) { 607fbb4a2e3Spbrook env->thumb = 1; 608fbb4a2e3Spbrook addr &= ~1; 609fbb4a2e3Spbrook } 610fbb4a2e3Spbrook env->regs[15] = addr; 611fbb4a2e3Spbrook 612fbb4a2e3Spbrook return 0; 613fbb4a2e3Spbrook } 614fbb4a2e3Spbrook 615426f5abcSPaul Brook static int do_strex(CPUARMState *env) 616426f5abcSPaul Brook { 617426f5abcSPaul Brook uint32_t val; 618426f5abcSPaul Brook int size; 619426f5abcSPaul Brook int rc = 1; 620426f5abcSPaul Brook int segv = 0; 621426f5abcSPaul Brook uint32_t addr; 622426f5abcSPaul Brook start_exclusive(); 623426f5abcSPaul Brook addr = env->exclusive_addr; 624426f5abcSPaul Brook if (addr != env->exclusive_test) { 625426f5abcSPaul Brook goto fail; 626426f5abcSPaul Brook } 627426f5abcSPaul Brook size = env->exclusive_info & 0xf; 628426f5abcSPaul Brook switch (size) { 629426f5abcSPaul Brook case 0: 630426f5abcSPaul Brook segv = get_user_u8(val, addr); 631426f5abcSPaul Brook break; 632426f5abcSPaul Brook case 1: 633426f5abcSPaul Brook segv = get_user_u16(val, addr); 634426f5abcSPaul Brook break; 635426f5abcSPaul Brook case 2: 636426f5abcSPaul Brook case 3: 637426f5abcSPaul Brook segv = get_user_u32(val, addr); 638426f5abcSPaul Brook break; 639f7001a3bSAurelien Jarno default: 640f7001a3bSAurelien Jarno abort(); 641426f5abcSPaul Brook } 642426f5abcSPaul Brook if (segv) { 643426f5abcSPaul Brook env->cp15.c6_data = addr; 644426f5abcSPaul Brook goto done; 645426f5abcSPaul Brook } 646426f5abcSPaul Brook if (val != env->exclusive_val) { 647426f5abcSPaul Brook goto fail; 648426f5abcSPaul Brook } 649426f5abcSPaul Brook if (size == 3) { 650426f5abcSPaul Brook segv = get_user_u32(val, addr + 4); 651426f5abcSPaul Brook if (segv) { 652426f5abcSPaul Brook env->cp15.c6_data = addr + 4; 653426f5abcSPaul Brook goto done; 654426f5abcSPaul Brook } 655426f5abcSPaul Brook if (val != env->exclusive_high) { 656426f5abcSPaul Brook goto fail; 657426f5abcSPaul Brook } 658426f5abcSPaul Brook } 659426f5abcSPaul Brook val = env->regs[(env->exclusive_info >> 8) & 0xf]; 660426f5abcSPaul Brook switch (size) { 661426f5abcSPaul Brook case 0: 662426f5abcSPaul Brook segv = put_user_u8(val, addr); 663426f5abcSPaul Brook break; 664426f5abcSPaul Brook case 1: 665426f5abcSPaul Brook segv = put_user_u16(val, addr); 666426f5abcSPaul Brook break; 667426f5abcSPaul Brook case 2: 668426f5abcSPaul Brook case 3: 669426f5abcSPaul Brook segv = put_user_u32(val, addr); 670426f5abcSPaul Brook break; 671426f5abcSPaul Brook } 672426f5abcSPaul Brook if (segv) { 673426f5abcSPaul Brook env->cp15.c6_data = addr; 674426f5abcSPaul Brook goto done; 675426f5abcSPaul Brook } 676426f5abcSPaul Brook if (size == 3) { 677426f5abcSPaul Brook val = env->regs[(env->exclusive_info >> 12) & 0xf]; 6782c9adbdaSPeter Maydell segv = put_user_u32(val, addr + 4); 679426f5abcSPaul Brook if (segv) { 680426f5abcSPaul Brook env->cp15.c6_data = addr + 4; 681426f5abcSPaul Brook goto done; 682426f5abcSPaul Brook } 683426f5abcSPaul Brook } 684426f5abcSPaul Brook rc = 0; 685426f5abcSPaul Brook fail: 686725b8a69SPaul Brook env->regs[15] += 4; 687426f5abcSPaul Brook env->regs[(env->exclusive_info >> 4) & 0xf] = rc; 688426f5abcSPaul Brook done: 689426f5abcSPaul Brook end_exclusive(); 690426f5abcSPaul Brook return segv; 691426f5abcSPaul Brook } 692426f5abcSPaul Brook 693b346ff46Sbellard void cpu_loop(CPUARMState *env) 694b346ff46Sbellard { 695b346ff46Sbellard int trapnr; 696b346ff46Sbellard unsigned int n, insn; 697c227f099SAnthony Liguori target_siginfo_t info; 698b5ff1b31Sbellard uint32_t addr; 699b346ff46Sbellard 700b346ff46Sbellard for(;;) { 701d5975363Spbrook cpu_exec_start(env); 702b346ff46Sbellard trapnr = cpu_arm_exec(env); 703d5975363Spbrook cpu_exec_end(env); 704b346ff46Sbellard switch(trapnr) { 705b346ff46Sbellard case EXCP_UDEF: 706c6981055Sbellard { 707c6981055Sbellard TaskState *ts = env->opaque; 708c6981055Sbellard uint32_t opcode; 7096d9a42beSaurel32 int rc; 710c6981055Sbellard 711c6981055Sbellard /* we handle the FPU emulation here, as Linux */ 712c6981055Sbellard /* we get the opcode */ 7132f619698Sbellard /* FIXME - what to do if get_user() fails? */ 714d8fd2954SPaul Brook get_user_code_u32(opcode, env->regs[15], env->bswap_code); 715c6981055Sbellard 7166d9a42beSaurel32 rc = EmulateAll(opcode, &ts->fpa, env); 7176d9a42beSaurel32 if (rc == 0) { /* illegal instruction */ 718b346ff46Sbellard info.si_signo = SIGILL; 719b346ff46Sbellard info.si_errno = 0; 720b346ff46Sbellard info.si_code = TARGET_ILL_ILLOPN; 721b346ff46Sbellard info._sifields._sigfault._addr = env->regs[15]; 722624f7979Spbrook queue_signal(env, info.si_signo, &info); 7236d9a42beSaurel32 } else if (rc < 0) { /* FP exception */ 7246d9a42beSaurel32 int arm_fpe=0; 7256d9a42beSaurel32 7266d9a42beSaurel32 /* translate softfloat flags to FPSR flags */ 7276d9a42beSaurel32 if (-rc & float_flag_invalid) 7286d9a42beSaurel32 arm_fpe |= BIT_IOC; 7296d9a42beSaurel32 if (-rc & float_flag_divbyzero) 7306d9a42beSaurel32 arm_fpe |= BIT_DZC; 7316d9a42beSaurel32 if (-rc & float_flag_overflow) 7326d9a42beSaurel32 arm_fpe |= BIT_OFC; 7336d9a42beSaurel32 if (-rc & float_flag_underflow) 7346d9a42beSaurel32 arm_fpe |= BIT_UFC; 7356d9a42beSaurel32 if (-rc & float_flag_inexact) 7366d9a42beSaurel32 arm_fpe |= BIT_IXC; 7376d9a42beSaurel32 7386d9a42beSaurel32 FPSR fpsr = ts->fpa.fpsr; 7396d9a42beSaurel32 //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); 7406d9a42beSaurel32 7416d9a42beSaurel32 if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ 7426d9a42beSaurel32 info.si_signo = SIGFPE; 7436d9a42beSaurel32 info.si_errno = 0; 7446d9a42beSaurel32 7456d9a42beSaurel32 /* ordered by priority, least first */ 7466d9a42beSaurel32 if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; 7476d9a42beSaurel32 if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; 7486d9a42beSaurel32 if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; 7496d9a42beSaurel32 if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; 7506d9a42beSaurel32 if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; 7516d9a42beSaurel32 7526d9a42beSaurel32 info._sifields._sigfault._addr = env->regs[15]; 753624f7979Spbrook queue_signal(env, info.si_signo, &info); 754c6981055Sbellard } else { 7556d9a42beSaurel32 env->regs[15] += 4; 7566d9a42beSaurel32 } 7576d9a42beSaurel32 7586d9a42beSaurel32 /* accumulate unenabled exceptions */ 7596d9a42beSaurel32 if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) 7606d9a42beSaurel32 fpsr |= BIT_IXC; 7616d9a42beSaurel32 if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) 7626d9a42beSaurel32 fpsr |= BIT_UFC; 7636d9a42beSaurel32 if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) 7646d9a42beSaurel32 fpsr |= BIT_OFC; 7656d9a42beSaurel32 if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) 7666d9a42beSaurel32 fpsr |= BIT_DZC; 7676d9a42beSaurel32 if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) 7686d9a42beSaurel32 fpsr |= BIT_IOC; 7696d9a42beSaurel32 ts->fpa.fpsr=fpsr; 7706d9a42beSaurel32 } else { /* everything OK */ 771c6981055Sbellard /* increment PC */ 772c6981055Sbellard env->regs[15] += 4; 773c6981055Sbellard } 774c6981055Sbellard } 775b346ff46Sbellard break; 776b346ff46Sbellard case EXCP_SWI: 77706c949e6Spbrook case EXCP_BKPT: 778b346ff46Sbellard { 779ce4defa0Spbrook env->eabi = 1; 780b346ff46Sbellard /* system call */ 78106c949e6Spbrook if (trapnr == EXCP_BKPT) { 78206c949e6Spbrook if (env->thumb) { 7832f619698Sbellard /* FIXME - what to do if get_user() fails? */ 784d8fd2954SPaul Brook get_user_code_u16(insn, env->regs[15], env->bswap_code); 78506c949e6Spbrook n = insn & 0xff; 78606c949e6Spbrook env->regs[15] += 2; 78706c949e6Spbrook } else { 7882f619698Sbellard /* FIXME - what to do if get_user() fails? */ 789d8fd2954SPaul Brook get_user_code_u32(insn, env->regs[15], env->bswap_code); 79006c949e6Spbrook n = (insn & 0xf) | ((insn >> 4) & 0xff0); 79106c949e6Spbrook env->regs[15] += 4; 79206c949e6Spbrook } 79306c949e6Spbrook } else { 794192c7bd9Sbellard if (env->thumb) { 7952f619698Sbellard /* FIXME - what to do if get_user() fails? */ 796d8fd2954SPaul Brook get_user_code_u16(insn, env->regs[15] - 2, 797d8fd2954SPaul Brook env->bswap_code); 798192c7bd9Sbellard n = insn & 0xff; 799192c7bd9Sbellard } else { 8002f619698Sbellard /* FIXME - what to do if get_user() fails? */ 801d8fd2954SPaul Brook get_user_code_u32(insn, env->regs[15] - 4, 802d8fd2954SPaul Brook env->bswap_code); 803b346ff46Sbellard n = insn & 0xffffff; 804192c7bd9Sbellard } 80506c949e6Spbrook } 806192c7bd9Sbellard 8076f1f31c0Sbellard if (n == ARM_NR_cacheflush) { 808dcfd14b3SBlue Swirl /* nop */ 809a4f81979Sbellard } else if (n == ARM_NR_semihosting 810a4f81979Sbellard || n == ARM_NR_thumb_semihosting) { 811a4f81979Sbellard env->regs[0] = do_arm_semihosting (env); 8123a1363acSAlexander Graf } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) { 813b346ff46Sbellard /* linux syscall */ 814ce4defa0Spbrook if (env->thumb || n == 0) { 815192c7bd9Sbellard n = env->regs[7]; 816192c7bd9Sbellard } else { 817b346ff46Sbellard n -= ARM_SYSCALL_BASE; 818ce4defa0Spbrook env->eabi = 0; 819192c7bd9Sbellard } 820fbb4a2e3Spbrook if ( n > ARM_NR_BASE) { 821fbb4a2e3Spbrook switch (n) { 822fbb4a2e3Spbrook case ARM_NR_cacheflush: 823dcfd14b3SBlue Swirl /* nop */ 824fbb4a2e3Spbrook break; 825fbb4a2e3Spbrook case ARM_NR_set_tls: 826fbb4a2e3Spbrook cpu_set_tls(env, env->regs[0]); 827fbb4a2e3Spbrook env->regs[0] = 0; 828fbb4a2e3Spbrook break; 829fbb4a2e3Spbrook default: 830fbb4a2e3Spbrook gemu_log("qemu: Unsupported ARM syscall: 0x%x\n", 831fbb4a2e3Spbrook n); 832fbb4a2e3Spbrook env->regs[0] = -TARGET_ENOSYS; 833fbb4a2e3Spbrook break; 834fbb4a2e3Spbrook } 835fbb4a2e3Spbrook } else { 836b346ff46Sbellard env->regs[0] = do_syscall(env, 837b346ff46Sbellard n, 838b346ff46Sbellard env->regs[0], 839b346ff46Sbellard env->regs[1], 840b346ff46Sbellard env->regs[2], 841b346ff46Sbellard env->regs[3], 842b346ff46Sbellard env->regs[4], 8435945cfcbSPeter Maydell env->regs[5], 8445945cfcbSPeter Maydell 0, 0); 845fbb4a2e3Spbrook } 846b346ff46Sbellard } else { 847b346ff46Sbellard goto error; 848b346ff46Sbellard } 849b346ff46Sbellard } 850b346ff46Sbellard break; 85143fff238Sbellard case EXCP_INTERRUPT: 85243fff238Sbellard /* just indicate that signals should be handled asap */ 85343fff238Sbellard break; 85468016c62Sbellard case EXCP_PREFETCH_ABORT: 855eae473c1Sbalrog addr = env->cp15.c6_insn; 856b5ff1b31Sbellard goto do_segv; 85768016c62Sbellard case EXCP_DATA_ABORT: 858eae473c1Sbalrog addr = env->cp15.c6_data; 859b5ff1b31Sbellard do_segv: 86068016c62Sbellard { 86168016c62Sbellard info.si_signo = SIGSEGV; 86268016c62Sbellard info.si_errno = 0; 86368016c62Sbellard /* XXX: check env->error_code */ 86468016c62Sbellard info.si_code = TARGET_SEGV_MAPERR; 865b5ff1b31Sbellard info._sifields._sigfault._addr = addr; 866624f7979Spbrook queue_signal(env, info.si_signo, &info); 86768016c62Sbellard } 86868016c62Sbellard break; 8691fddef4bSbellard case EXCP_DEBUG: 8701fddef4bSbellard { 8711fddef4bSbellard int sig; 8721fddef4bSbellard 8731fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 8741fddef4bSbellard if (sig) 8751fddef4bSbellard { 8761fddef4bSbellard info.si_signo = sig; 8771fddef4bSbellard info.si_errno = 0; 8781fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 879624f7979Spbrook queue_signal(env, info.si_signo, &info); 8801fddef4bSbellard } 8811fddef4bSbellard } 8821fddef4bSbellard break; 883fbb4a2e3Spbrook case EXCP_KERNEL_TRAP: 884fbb4a2e3Spbrook if (do_kernel_trap(env)) 885fbb4a2e3Spbrook goto error; 886fbb4a2e3Spbrook break; 887426f5abcSPaul Brook case EXCP_STREX: 888426f5abcSPaul Brook if (do_strex(env)) { 889426f5abcSPaul Brook addr = env->cp15.c6_data; 890426f5abcSPaul Brook goto do_segv; 891426f5abcSPaul Brook } 892e9273455SPaul Brook break; 893b346ff46Sbellard default: 894b346ff46Sbellard error: 895b346ff46Sbellard fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 896b346ff46Sbellard trapnr); 8977fe48483Sbellard cpu_dump_state(env, stderr, fprintf, 0); 898b346ff46Sbellard abort(); 899b346ff46Sbellard } 900b346ff46Sbellard process_pending_signals(env); 901b346ff46Sbellard } 902b346ff46Sbellard } 903b346ff46Sbellard 904b346ff46Sbellard #endif 9051b6b029eSbellard 906d2fbca94SGuan Xuetao #ifdef TARGET_UNICORE32 907d2fbca94SGuan Xuetao 90805390248SAndreas Färber void cpu_loop(CPUUniCore32State *env) 909d2fbca94SGuan Xuetao { 910d2fbca94SGuan Xuetao int trapnr; 911d2fbca94SGuan Xuetao unsigned int n, insn; 912d2fbca94SGuan Xuetao target_siginfo_t info; 913d2fbca94SGuan Xuetao 914d2fbca94SGuan Xuetao for (;;) { 915d2fbca94SGuan Xuetao cpu_exec_start(env); 916d2fbca94SGuan Xuetao trapnr = uc32_cpu_exec(env); 917d2fbca94SGuan Xuetao cpu_exec_end(env); 918d2fbca94SGuan Xuetao switch (trapnr) { 919d2fbca94SGuan Xuetao case UC32_EXCP_PRIV: 920d2fbca94SGuan Xuetao { 921d2fbca94SGuan Xuetao /* system call */ 922d2fbca94SGuan Xuetao get_user_u32(insn, env->regs[31] - 4); 923d2fbca94SGuan Xuetao n = insn & 0xffffff; 924d2fbca94SGuan Xuetao 925d2fbca94SGuan Xuetao if (n >= UC32_SYSCALL_BASE) { 926d2fbca94SGuan Xuetao /* linux syscall */ 927d2fbca94SGuan Xuetao n -= UC32_SYSCALL_BASE; 928d2fbca94SGuan Xuetao if (n == UC32_SYSCALL_NR_set_tls) { 929d2fbca94SGuan Xuetao cpu_set_tls(env, env->regs[0]); 930d2fbca94SGuan Xuetao env->regs[0] = 0; 931d2fbca94SGuan Xuetao } else { 932d2fbca94SGuan Xuetao env->regs[0] = do_syscall(env, 933d2fbca94SGuan Xuetao n, 934d2fbca94SGuan Xuetao env->regs[0], 935d2fbca94SGuan Xuetao env->regs[1], 936d2fbca94SGuan Xuetao env->regs[2], 937d2fbca94SGuan Xuetao env->regs[3], 938d2fbca94SGuan Xuetao env->regs[4], 9395945cfcbSPeter Maydell env->regs[5], 9405945cfcbSPeter Maydell 0, 0); 941d2fbca94SGuan Xuetao } 942d2fbca94SGuan Xuetao } else { 943d2fbca94SGuan Xuetao goto error; 944d2fbca94SGuan Xuetao } 945d2fbca94SGuan Xuetao } 946d2fbca94SGuan Xuetao break; 947d48813ddSGuan Xuetao case UC32_EXCP_DTRAP: 948d48813ddSGuan Xuetao case UC32_EXCP_ITRAP: 949d2fbca94SGuan Xuetao info.si_signo = SIGSEGV; 950d2fbca94SGuan Xuetao info.si_errno = 0; 951d2fbca94SGuan Xuetao /* XXX: check env->error_code */ 952d2fbca94SGuan Xuetao info.si_code = TARGET_SEGV_MAPERR; 953d2fbca94SGuan Xuetao info._sifields._sigfault._addr = env->cp0.c4_faultaddr; 954d2fbca94SGuan Xuetao queue_signal(env, info.si_signo, &info); 955d2fbca94SGuan Xuetao break; 956d2fbca94SGuan Xuetao case EXCP_INTERRUPT: 957d2fbca94SGuan Xuetao /* just indicate that signals should be handled asap */ 958d2fbca94SGuan Xuetao break; 959d2fbca94SGuan Xuetao case EXCP_DEBUG: 960d2fbca94SGuan Xuetao { 961d2fbca94SGuan Xuetao int sig; 962d2fbca94SGuan Xuetao 963d2fbca94SGuan Xuetao sig = gdb_handlesig(env, TARGET_SIGTRAP); 964d2fbca94SGuan Xuetao if (sig) { 965d2fbca94SGuan Xuetao info.si_signo = sig; 966d2fbca94SGuan Xuetao info.si_errno = 0; 967d2fbca94SGuan Xuetao info.si_code = TARGET_TRAP_BRKPT; 968d2fbca94SGuan Xuetao queue_signal(env, info.si_signo, &info); 969d2fbca94SGuan Xuetao } 970d2fbca94SGuan Xuetao } 971d2fbca94SGuan Xuetao break; 972d2fbca94SGuan Xuetao default: 973d2fbca94SGuan Xuetao goto error; 974d2fbca94SGuan Xuetao } 975d2fbca94SGuan Xuetao process_pending_signals(env); 976d2fbca94SGuan Xuetao } 977d2fbca94SGuan Xuetao 978d2fbca94SGuan Xuetao error: 979d2fbca94SGuan Xuetao fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); 980d2fbca94SGuan Xuetao cpu_dump_state(env, stderr, fprintf, 0); 981d2fbca94SGuan Xuetao abort(); 982d2fbca94SGuan Xuetao } 983d2fbca94SGuan Xuetao #endif 984d2fbca94SGuan Xuetao 98593ac68bcSbellard #ifdef TARGET_SPARC 986ed23fbd9Sblueswir1 #define SPARC64_STACK_BIAS 2047 98793ac68bcSbellard 988060366c5Sbellard //#define DEBUG_WIN 989060366c5Sbellard 9902623cbafSbellard /* WARNING: dealing with register windows _is_ complicated. More info 9912623cbafSbellard can be found at http://www.sics.se/~psm/sparcstack.html */ 992060366c5Sbellard static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) 993060366c5Sbellard { 9941a14026eSblueswir1 index = (index + cwp * 16) % (16 * env->nwindows); 995060366c5Sbellard /* wrap handling : if cwp is on the last window, then we use the 996060366c5Sbellard registers 'after' the end */ 9971a14026eSblueswir1 if (index < 8 && env->cwp == env->nwindows - 1) 9981a14026eSblueswir1 index += 16 * env->nwindows; 999060366c5Sbellard return index; 1000060366c5Sbellard } 1001060366c5Sbellard 10022623cbafSbellard /* save the register window 'cwp1' */ 10032623cbafSbellard static inline void save_window_offset(CPUSPARCState *env, int cwp1) 1004060366c5Sbellard { 10052623cbafSbellard unsigned int i; 1006992f48a0Sblueswir1 abi_ulong sp_ptr; 1007060366c5Sbellard 100853a5960aSpbrook sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; 1009ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64 1010ed23fbd9Sblueswir1 if (sp_ptr & 3) 1011ed23fbd9Sblueswir1 sp_ptr += SPARC64_STACK_BIAS; 1012ed23fbd9Sblueswir1 #endif 1013060366c5Sbellard #if defined(DEBUG_WIN) 10142daf0284Sblueswir1 printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", 10152daf0284Sblueswir1 sp_ptr, cwp1); 1016060366c5Sbellard #endif 10172623cbafSbellard for(i = 0; i < 16; i++) { 10182f619698Sbellard /* FIXME - what to do if put_user() fails? */ 10192f619698Sbellard put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); 1020992f48a0Sblueswir1 sp_ptr += sizeof(abi_ulong); 10212623cbafSbellard } 1022060366c5Sbellard } 1023060366c5Sbellard 1024060366c5Sbellard static void save_window(CPUSPARCState *env) 1025060366c5Sbellard { 10265ef54116Sbellard #ifndef TARGET_SPARC64 10272623cbafSbellard unsigned int new_wim; 10281a14026eSblueswir1 new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) & 10291a14026eSblueswir1 ((1LL << env->nwindows) - 1); 10301a14026eSblueswir1 save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); 10312623cbafSbellard env->wim = new_wim; 10325ef54116Sbellard #else 10331a14026eSblueswir1 save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2)); 10345ef54116Sbellard env->cansave++; 10355ef54116Sbellard env->canrestore--; 10365ef54116Sbellard #endif 1037060366c5Sbellard } 1038060366c5Sbellard 1039060366c5Sbellard static void restore_window(CPUSPARCState *env) 1040060366c5Sbellard { 1041eda52953Sblueswir1 #ifndef TARGET_SPARC64 1042eda52953Sblueswir1 unsigned int new_wim; 1043eda52953Sblueswir1 #endif 1044eda52953Sblueswir1 unsigned int i, cwp1; 1045992f48a0Sblueswir1 abi_ulong sp_ptr; 1046060366c5Sbellard 1047eda52953Sblueswir1 #ifndef TARGET_SPARC64 10481a14026eSblueswir1 new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) & 10491a14026eSblueswir1 ((1LL << env->nwindows) - 1); 1050eda52953Sblueswir1 #endif 1051060366c5Sbellard 1052060366c5Sbellard /* restore the invalid window */ 10531a14026eSblueswir1 cwp1 = cpu_cwp_inc(env, env->cwp + 1); 105453a5960aSpbrook sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; 1055ed23fbd9Sblueswir1 #ifdef TARGET_SPARC64 1056ed23fbd9Sblueswir1 if (sp_ptr & 3) 1057ed23fbd9Sblueswir1 sp_ptr += SPARC64_STACK_BIAS; 1058ed23fbd9Sblueswir1 #endif 1059060366c5Sbellard #if defined(DEBUG_WIN) 10602daf0284Sblueswir1 printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", 10612daf0284Sblueswir1 sp_ptr, cwp1); 1062060366c5Sbellard #endif 10632623cbafSbellard for(i = 0; i < 16; i++) { 10642f619698Sbellard /* FIXME - what to do if get_user() fails? */ 10652f619698Sbellard get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); 1066992f48a0Sblueswir1 sp_ptr += sizeof(abi_ulong); 10672623cbafSbellard } 10685ef54116Sbellard #ifdef TARGET_SPARC64 10695ef54116Sbellard env->canrestore++; 10701a14026eSblueswir1 if (env->cleanwin < env->nwindows - 1) 10715ef54116Sbellard env->cleanwin++; 10725ef54116Sbellard env->cansave--; 1073eda52953Sblueswir1 #else 1074eda52953Sblueswir1 env->wim = new_wim; 10755ef54116Sbellard #endif 1076060366c5Sbellard } 1077060366c5Sbellard 1078060366c5Sbellard static void flush_windows(CPUSPARCState *env) 1079060366c5Sbellard { 1080060366c5Sbellard int offset, cwp1; 10812623cbafSbellard 10822623cbafSbellard offset = 1; 1083060366c5Sbellard for(;;) { 1084060366c5Sbellard /* if restore would invoke restore_window(), then we can stop */ 10851a14026eSblueswir1 cwp1 = cpu_cwp_inc(env, env->cwp + offset); 1086eda52953Sblueswir1 #ifndef TARGET_SPARC64 1087060366c5Sbellard if (env->wim & (1 << cwp1)) 1088060366c5Sbellard break; 1089eda52953Sblueswir1 #else 1090eda52953Sblueswir1 if (env->canrestore == 0) 1091eda52953Sblueswir1 break; 1092eda52953Sblueswir1 env->cansave++; 1093eda52953Sblueswir1 env->canrestore--; 1094eda52953Sblueswir1 #endif 10952623cbafSbellard save_window_offset(env, cwp1); 1096060366c5Sbellard offset++; 1097060366c5Sbellard } 10981a14026eSblueswir1 cwp1 = cpu_cwp_inc(env, env->cwp + 1); 1099eda52953Sblueswir1 #ifndef TARGET_SPARC64 1100eda52953Sblueswir1 /* set wim so that restore will reload the registers */ 11012623cbafSbellard env->wim = 1 << cwp1; 1102eda52953Sblueswir1 #endif 11032623cbafSbellard #if defined(DEBUG_WIN) 11042623cbafSbellard printf("flush_windows: nb=%d\n", offset - 1); 110580a9d035Sbellard #endif 11062623cbafSbellard } 1107060366c5Sbellard 110893ac68bcSbellard void cpu_loop (CPUSPARCState *env) 110993ac68bcSbellard { 11102cc20260SRichard Henderson int trapnr; 11112cc20260SRichard Henderson abi_long ret; 1112c227f099SAnthony Liguori target_siginfo_t info; 111393ac68bcSbellard 111493ac68bcSbellard while (1) { 111593ac68bcSbellard trapnr = cpu_sparc_exec (env); 111693ac68bcSbellard 111793ac68bcSbellard switch (trapnr) { 11185ef54116Sbellard #ifndef TARGET_SPARC64 1119060366c5Sbellard case 0x88: 1120060366c5Sbellard case 0x90: 11215ef54116Sbellard #else 1122cb33da57Sblueswir1 case 0x110: 11235ef54116Sbellard case 0x16d: 11245ef54116Sbellard #endif 1125060366c5Sbellard ret = do_syscall (env, env->gregs[1], 1126060366c5Sbellard env->regwptr[0], env->regwptr[1], 1127060366c5Sbellard env->regwptr[2], env->regwptr[3], 11285945cfcbSPeter Maydell env->regwptr[4], env->regwptr[5], 11295945cfcbSPeter Maydell 0, 0); 11302cc20260SRichard Henderson if ((abi_ulong)ret >= (abi_ulong)(-515)) { 1131992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) 113227908725Sbellard env->xcc |= PSR_CARRY; 113327908725Sbellard #else 113493ac68bcSbellard env->psr |= PSR_CARRY; 113527908725Sbellard #endif 1136060366c5Sbellard ret = -ret; 1137060366c5Sbellard } else { 1138992f48a0Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) 113927908725Sbellard env->xcc &= ~PSR_CARRY; 114027908725Sbellard #else 1141060366c5Sbellard env->psr &= ~PSR_CARRY; 114227908725Sbellard #endif 1143060366c5Sbellard } 1144060366c5Sbellard env->regwptr[0] = ret; 1145060366c5Sbellard /* next instruction */ 1146060366c5Sbellard env->pc = env->npc; 1147060366c5Sbellard env->npc = env->npc + 4; 1148060366c5Sbellard break; 1149060366c5Sbellard case 0x83: /* flush windows */ 1150992f48a0Sblueswir1 #ifdef TARGET_ABI32 1151992f48a0Sblueswir1 case 0x103: 1152992f48a0Sblueswir1 #endif 11532623cbafSbellard flush_windows(env); 1154060366c5Sbellard /* next instruction */ 1155060366c5Sbellard env->pc = env->npc; 1156060366c5Sbellard env->npc = env->npc + 4; 1157060366c5Sbellard break; 11583475187dSbellard #ifndef TARGET_SPARC64 1159060366c5Sbellard case TT_WIN_OVF: /* window overflow */ 1160060366c5Sbellard save_window(env); 1161060366c5Sbellard break; 1162060366c5Sbellard case TT_WIN_UNF: /* window underflow */ 1163060366c5Sbellard restore_window(env); 116493ac68bcSbellard break; 116561ff6f58Sbellard case TT_TFAULT: 116661ff6f58Sbellard case TT_DFAULT: 116761ff6f58Sbellard { 116859f7182fSRichard Henderson info.si_signo = TARGET_SIGSEGV; 116961ff6f58Sbellard info.si_errno = 0; 117061ff6f58Sbellard /* XXX: check env->error_code */ 117161ff6f58Sbellard info.si_code = TARGET_SEGV_MAPERR; 117261ff6f58Sbellard info._sifields._sigfault._addr = env->mmuregs[4]; 1173624f7979Spbrook queue_signal(env, info.si_signo, &info); 117461ff6f58Sbellard } 117561ff6f58Sbellard break; 11763475187dSbellard #else 11775ef54116Sbellard case TT_SPILL: /* window overflow */ 11785ef54116Sbellard save_window(env); 11795ef54116Sbellard break; 11805ef54116Sbellard case TT_FILL: /* window underflow */ 11815ef54116Sbellard restore_window(env); 11825ef54116Sbellard break; 11837f84a729Sblueswir1 case TT_TFAULT: 11847f84a729Sblueswir1 case TT_DFAULT: 11857f84a729Sblueswir1 { 118659f7182fSRichard Henderson info.si_signo = TARGET_SIGSEGV; 11877f84a729Sblueswir1 info.si_errno = 0; 11887f84a729Sblueswir1 /* XXX: check env->error_code */ 11897f84a729Sblueswir1 info.si_code = TARGET_SEGV_MAPERR; 11907f84a729Sblueswir1 if (trapnr == TT_DFAULT) 11917f84a729Sblueswir1 info._sifields._sigfault._addr = env->dmmuregs[4]; 11927f84a729Sblueswir1 else 11938194f35aSIgor Kovalenko info._sifields._sigfault._addr = cpu_tsptr(env)->tpc; 1194624f7979Spbrook queue_signal(env, info.si_signo, &info); 11957f84a729Sblueswir1 } 11967f84a729Sblueswir1 break; 119727524dc3Sbellard #ifndef TARGET_ABI32 11985bfb56b2Sblueswir1 case 0x16e: 11995bfb56b2Sblueswir1 flush_windows(env); 12005bfb56b2Sblueswir1 sparc64_get_context(env); 12015bfb56b2Sblueswir1 break; 12025bfb56b2Sblueswir1 case 0x16f: 12035bfb56b2Sblueswir1 flush_windows(env); 12045bfb56b2Sblueswir1 sparc64_set_context(env); 12055bfb56b2Sblueswir1 break; 12063475187dSbellard #endif 120727524dc3Sbellard #endif 120848dc41ebSbellard case EXCP_INTERRUPT: 120948dc41ebSbellard /* just indicate that signals should be handled asap */ 1210e80cfcfcSbellard break; 121175f22e4eSRichard Henderson case TT_ILL_INSN: 121275f22e4eSRichard Henderson { 121375f22e4eSRichard Henderson info.si_signo = TARGET_SIGILL; 121475f22e4eSRichard Henderson info.si_errno = 0; 121575f22e4eSRichard Henderson info.si_code = TARGET_ILL_ILLOPC; 121675f22e4eSRichard Henderson info._sifields._sigfault._addr = env->pc; 121775f22e4eSRichard Henderson queue_signal(env, info.si_signo, &info); 121875f22e4eSRichard Henderson } 121975f22e4eSRichard Henderson break; 12201fddef4bSbellard case EXCP_DEBUG: 12211fddef4bSbellard { 12221fddef4bSbellard int sig; 12231fddef4bSbellard 12241fddef4bSbellard sig = gdb_handlesig (env, TARGET_SIGTRAP); 12251fddef4bSbellard if (sig) 12261fddef4bSbellard { 12271fddef4bSbellard info.si_signo = sig; 12281fddef4bSbellard info.si_errno = 0; 12291fddef4bSbellard info.si_code = TARGET_TRAP_BRKPT; 1230624f7979Spbrook queue_signal(env, info.si_signo, &info); 12311fddef4bSbellard } 12321fddef4bSbellard } 12331fddef4bSbellard break; 123493ac68bcSbellard default: 1235060366c5Sbellard printf ("Unhandled trap: 0x%x\n", trapnr); 12367fe48483Sbellard cpu_dump_state(env, stderr, fprintf, 0); 123793ac68bcSbellard exit (1); 123893ac68bcSbellard } 123993ac68bcSbellard process_pending_signals (env); 124093ac68bcSbellard } 124193ac68bcSbellard } 124293ac68bcSbellard 124393ac68bcSbellard #endif 124493ac68bcSbellard 124567867308Sbellard #ifdef TARGET_PPC 124605390248SAndreas Färber static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env) 12479fddaa0cSbellard { 12489fddaa0cSbellard /* TO FIX */ 12499fddaa0cSbellard return 0; 12509fddaa0cSbellard } 12519fddaa0cSbellard 125205390248SAndreas Färber uint64_t cpu_ppc_load_tbl(CPUPPCState *env) 12539fddaa0cSbellard { 1254e3ea6529SAlexander Graf return cpu_ppc_get_tb(env); 12559fddaa0cSbellard } 12569fddaa0cSbellard 125705390248SAndreas Färber uint32_t cpu_ppc_load_tbu(CPUPPCState *env) 12589fddaa0cSbellard { 12599fddaa0cSbellard return cpu_ppc_get_tb(env) >> 32; 12609fddaa0cSbellard } 12619fddaa0cSbellard 126205390248SAndreas Färber uint64_t cpu_ppc_load_atbl(CPUPPCState *env) 12639fddaa0cSbellard { 1264b711de95SAurelien Jarno return cpu_ppc_get_tb(env); 12659fddaa0cSbellard } 12669fddaa0cSbellard 126705390248SAndreas Färber uint32_t cpu_ppc_load_atbu(CPUPPCState *env) 12689fddaa0cSbellard { 1269a062e36cSj_mayer return cpu_ppc_get_tb(env) >> 32; 12709fddaa0cSbellard } 12719fddaa0cSbellard 127205390248SAndreas Färber uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env) 127376a66253Sj_mayer __attribute__ (( alias ("cpu_ppc_load_tbu") )); 127476a66253Sj_mayer 127505390248SAndreas Färber uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env) 12769fddaa0cSbellard { 127776a66253Sj_mayer return cpu_ppc_load_tbl(env) & 0x3FFFFF80; 12789fddaa0cSbellard } 12799fddaa0cSbellard 1280a750fc0bSj_mayer /* XXX: to be fixed */ 128173b01960SAlexander Graf int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp) 1282a750fc0bSj_mayer { 1283a750fc0bSj_mayer return -1; 1284a750fc0bSj_mayer } 1285a750fc0bSj_mayer 128673b01960SAlexander Graf int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val) 1287a750fc0bSj_mayer { 1288a750fc0bSj_mayer return -1; 1289a750fc0bSj_mayer } 1290a750fc0bSj_mayer 1291001faf32SBlue Swirl #define EXCP_DUMP(env, fmt, ...) \ 1292e1833e1fSj_mayer do { \ 1293001faf32SBlue Swirl fprintf(stderr, fmt , ## __VA_ARGS__); \ 1294e1833e1fSj_mayer cpu_dump_state(env, stderr, fprintf, 0); \ 1295001faf32SBlue Swirl qemu_log(fmt, ## __VA_ARGS__); \ 1296eeacee4dSBlue Swirl if (qemu_log_enabled()) { \ 129793fcfe39Saliguori log_cpu_state(env, 0); \ 1298eeacee4dSBlue Swirl } \ 1299e1833e1fSj_mayer } while (0) 1300e1833e1fSj_mayer 130156f066bbSNathan Froyd static int do_store_exclusive(CPUPPCState *env) 130256f066bbSNathan Froyd { 130356f066bbSNathan Froyd target_ulong addr; 130456f066bbSNathan Froyd target_ulong page_addr; 130556f066bbSNathan Froyd target_ulong val; 130656f066bbSNathan Froyd int flags; 130756f066bbSNathan Froyd int segv = 0; 130856f066bbSNathan Froyd 130956f066bbSNathan Froyd addr = env->reserve_ea; 131056f066bbSNathan Froyd page_addr = addr & TARGET_PAGE_MASK; 131156f066bbSNathan Froyd start_exclusive(); 131256f066bbSNathan Froyd mmap_lock(); 131356f066bbSNathan Froyd flags = page_get_flags(page_addr); 131456f066bbSNathan Froyd if ((flags & PAGE_READ) == 0) { 131556f066bbSNathan Froyd segv = 1; 131656f066bbSNathan Froyd } else { 131756f066bbSNathan Froyd int reg = env->reserve_info & 0x1f; 131856f066bbSNathan Froyd int size = (env->reserve_info >> 5) & 0xf; 131956f066bbSNathan Froyd int stored = 0; 132056f066bbSNathan Froyd 132156f066bbSNathan Froyd if (addr == env->reserve_addr) { 132256f066bbSNathan Froyd switch (size) { 132356f066bbSNathan Froyd case 1: segv = get_user_u8(val, addr); break; 132456f066bbSNathan Froyd case 2: segv = get_user_u16(val, addr); break; 132556f066bbSNathan Froyd case 4: segv = get_user_u32(val, addr); break; 132656f066bbSNathan Froyd #if defined(TARGET_PPC64) 132756f066bbSNathan Froyd case 8: segv = get_user_u64(val, addr); break; 132856f066bbSNathan Froyd #endif 132956f066bbSNathan Froyd default: abort(); 133056f066bbSNathan Froyd } 133156f066bbSNathan Froyd if (!segv && val == env->reserve_val) { 133256f066bbSNathan Froyd val = env->gpr[reg]; 133356f066bbSNathan Froyd switch (size) { 133456f066bbSNathan Froyd case 1: segv = put_user_u8(val, addr); break; 133556f066bbSNathan Froyd case 2: segv = put_user_u16(val, addr); break; 133656f066bbSNathan Froyd case 4: segv = put_user_u32(val, addr); break; 133756f066bbSNathan Froyd #if defined(TARGET_PPC64) 133856f066bbSNathan Froyd case 8: segv = put_user_u64(val, addr); break; 133956f066bbSNathan Froyd #endif 134056f066bbSNathan Froyd default: abort(); 134156f066bbSNathan Froyd } 134256f066bbSNathan Froyd if (!segv) { 134356f066bbSNathan Froyd stored = 1; 134456f066bbSNathan Froyd } 134556f066bbSNathan Froyd } 134656f066bbSNathan Froyd } 134756f066bbSNathan Froyd env->crf[0] = (stored << 1) | xer_so; 134856f066bbSNathan Froyd env->reserve_addr = (target_ulong)-1; 134956f066bbSNathan Froyd } 135056f066bbSNathan Froyd if (!segv) { 135156f066bbSNathan Froyd env->nip += 4; 135256f066bbSNathan Froyd } 135356f066bbSNathan Froyd mmap_unlock(); 135456f066bbSNathan Froyd end_exclusive(); 135556f066bbSNathan Froyd return segv; 135656f066bbSNathan Froyd } 135756f066bbSNathan Froyd 135867867308Sbellard void cpu_loop(CPUPPCState *env) 135967867308Sbellard { 1360c227f099SAnthony Liguori target_siginfo_t info; 136161190b14Sbellard int trapnr; 13629e0e2f96SRichard Henderson target_ulong ret; 136367867308Sbellard 136467867308Sbellard for(;;) { 136556f066bbSNathan Froyd cpu_exec_start(env); 136667867308Sbellard trapnr = cpu_ppc_exec(env); 136756f066bbSNathan Froyd cpu_exec_end(env); 136867867308Sbellard switch(trapnr) { 1369e1833e1fSj_mayer case POWERPC_EXCP_NONE: 1370e1833e1fSj_mayer /* Just go on */ 137167867308Sbellard break; 1372e1833e1fSj_mayer case POWERPC_EXCP_CRITICAL: /* Critical input */ 1373e1833e1fSj_mayer cpu_abort(env, "Critical interrupt while in user mode. " 1374e1833e1fSj_mayer "Aborting\n"); 1375e1833e1fSj_mayer break; 1376e1833e1fSj_mayer case POWERPC_EXCP_MCHECK: /* Machine check exception */ 1377e1833e1fSj_mayer cpu_abort(env, "Machine check exception while in user mode. " 1378e1833e1fSj_mayer "Aborting\n"); 1379e1833e1fSj_mayer break; 1380e1833e1fSj_mayer case POWERPC_EXCP_DSI: /* Data storage exception */ 138190e189ecSBlue Swirl EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n", 1382e1833e1fSj_mayer env->spr[SPR_DAR]); 1383e1833e1fSj_mayer /* XXX: check this. Seems bugged */ 1384e1833e1fSj_mayer switch (env->error_code & 0xFF000000) { 1385e1833e1fSj_mayer case 0x40000000: 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 case 0x04000000: 1391e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1392e1833e1fSj_mayer info.si_errno = 0; 1393e1833e1fSj_mayer info.si_code = TARGET_ILL_ILLADR; 1394e1833e1fSj_mayer break; 1395e1833e1fSj_mayer case 0x08000000: 1396e1833e1fSj_mayer info.si_signo = TARGET_SIGSEGV; 1397e1833e1fSj_mayer info.si_errno = 0; 1398e1833e1fSj_mayer info.si_code = TARGET_SEGV_ACCERR; 1399e1833e1fSj_mayer break; 1400e1833e1fSj_mayer default: 1401e1833e1fSj_mayer /* Let's send a regular segfault... */ 1402e1833e1fSj_mayer EXCP_DUMP(env, "Invalid segfault errno (%02x)\n", 1403e1833e1fSj_mayer env->error_code); 1404e1833e1fSj_mayer info.si_signo = TARGET_SIGSEGV; 1405e1833e1fSj_mayer info.si_errno = 0; 1406e1833e1fSj_mayer info.si_code = TARGET_SEGV_MAPERR; 1407e1833e1fSj_mayer break; 1408e1833e1fSj_mayer } 1409e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip; 1410624f7979Spbrook queue_signal(env, info.si_signo, &info); 1411e1833e1fSj_mayer break; 1412e1833e1fSj_mayer case POWERPC_EXCP_ISI: /* Instruction storage exception */ 141390e189ecSBlue Swirl EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx 141490e189ecSBlue Swirl "\n", env->spr[SPR_SRR0]); 1415e1833e1fSj_mayer /* XXX: check this */ 1416e1833e1fSj_mayer switch (env->error_code & 0xFF000000) { 1417e1833e1fSj_mayer case 0x40000000: 1418e1833e1fSj_mayer info.si_signo = TARGET_SIGSEGV; 1419e1833e1fSj_mayer info.si_errno = 0; 1420e1833e1fSj_mayer info.si_code = TARGET_SEGV_MAPERR; 1421e1833e1fSj_mayer break; 1422e1833e1fSj_mayer case 0x10000000: 1423e1833e1fSj_mayer case 0x08000000: 1424e1833e1fSj_mayer info.si_signo = TARGET_SIGSEGV; 1425e1833e1fSj_mayer info.si_errno = 0; 1426e1833e1fSj_mayer info.si_code = TARGET_SEGV_ACCERR; 1427e1833e1fSj_mayer break; 1428e1833e1fSj_mayer default: 1429e1833e1fSj_mayer /* Let's send a regular segfault... */ 1430e1833e1fSj_mayer EXCP_DUMP(env, "Invalid segfault errno (%02x)\n", 1431e1833e1fSj_mayer env->error_code); 1432e1833e1fSj_mayer info.si_signo = TARGET_SIGSEGV; 1433e1833e1fSj_mayer info.si_errno = 0; 1434e1833e1fSj_mayer info.si_code = TARGET_SEGV_MAPERR; 1435e1833e1fSj_mayer break; 1436e1833e1fSj_mayer } 1437e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1438624f7979Spbrook queue_signal(env, info.si_signo, &info); 1439e1833e1fSj_mayer break; 1440e1833e1fSj_mayer case POWERPC_EXCP_EXTERNAL: /* External input */ 1441e1833e1fSj_mayer cpu_abort(env, "External interrupt while in user mode. " 1442e1833e1fSj_mayer "Aborting\n"); 1443e1833e1fSj_mayer break; 1444e1833e1fSj_mayer case POWERPC_EXCP_ALIGN: /* Alignment exception */ 1445e1833e1fSj_mayer EXCP_DUMP(env, "Unaligned memory access\n"); 1446e1833e1fSj_mayer /* XXX: check this */ 1447e1833e1fSj_mayer info.si_signo = TARGET_SIGBUS; 1448e1833e1fSj_mayer info.si_errno = 0; 1449e1833e1fSj_mayer info.si_code = TARGET_BUS_ADRALN; 1450e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1451624f7979Spbrook queue_signal(env, info.si_signo, &info); 1452e1833e1fSj_mayer break; 1453e1833e1fSj_mayer case POWERPC_EXCP_PROGRAM: /* Program exception */ 1454e1833e1fSj_mayer /* XXX: check this */ 1455e1833e1fSj_mayer switch (env->error_code & ~0xF) { 1456e1833e1fSj_mayer case POWERPC_EXCP_FP: 1457e1833e1fSj_mayer EXCP_DUMP(env, "Floating point program exception\n"); 1458e1833e1fSj_mayer info.si_signo = TARGET_SIGFPE; 1459e1833e1fSj_mayer info.si_errno = 0; 1460e1833e1fSj_mayer switch (env->error_code & 0xF) { 1461e1833e1fSj_mayer case POWERPC_EXCP_FP_OX: 1462e1833e1fSj_mayer info.si_code = TARGET_FPE_FLTOVF; 1463e1833e1fSj_mayer break; 1464e1833e1fSj_mayer case POWERPC_EXCP_FP_UX: 1465e1833e1fSj_mayer info.si_code = TARGET_FPE_FLTUND; 1466e1833e1fSj_mayer break; 1467e1833e1fSj_mayer case POWERPC_EXCP_FP_ZX: 1468e1833e1fSj_mayer case POWERPC_EXCP_FP_VXZDZ: 1469e1833e1fSj_mayer info.si_code = TARGET_FPE_FLTDIV; 1470e1833e1fSj_mayer break; 1471e1833e1fSj_mayer case POWERPC_EXCP_FP_XX: 1472e1833e1fSj_mayer info.si_code = TARGET_FPE_FLTRES; 1473e1833e1fSj_mayer break; 1474e1833e1fSj_mayer case POWERPC_EXCP_FP_VXSOFT: 1475e1833e1fSj_mayer info.si_code = TARGET_FPE_FLTINV; 1476e1833e1fSj_mayer break; 14777c58044cSj_mayer case POWERPC_EXCP_FP_VXSNAN: 1478e1833e1fSj_mayer case POWERPC_EXCP_FP_VXISI: 1479e1833e1fSj_mayer case POWERPC_EXCP_FP_VXIDI: 1480e1833e1fSj_mayer case POWERPC_EXCP_FP_VXIMZ: 1481e1833e1fSj_mayer case POWERPC_EXCP_FP_VXVC: 1482e1833e1fSj_mayer case POWERPC_EXCP_FP_VXSQRT: 1483e1833e1fSj_mayer case POWERPC_EXCP_FP_VXCVI: 1484e1833e1fSj_mayer info.si_code = TARGET_FPE_FLTSUB; 1485e1833e1fSj_mayer break; 1486e1833e1fSj_mayer default: 1487e1833e1fSj_mayer EXCP_DUMP(env, "Unknown floating point exception (%02x)\n", 1488e1833e1fSj_mayer env->error_code); 1489e1833e1fSj_mayer break; 1490e1833e1fSj_mayer } 1491e1833e1fSj_mayer break; 1492e1833e1fSj_mayer case POWERPC_EXCP_INVAL: 1493e1833e1fSj_mayer EXCP_DUMP(env, "Invalid instruction\n"); 1494e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1495e1833e1fSj_mayer info.si_errno = 0; 1496e1833e1fSj_mayer switch (env->error_code & 0xF) { 1497e1833e1fSj_mayer case POWERPC_EXCP_INVAL_INVAL: 1498e1833e1fSj_mayer info.si_code = TARGET_ILL_ILLOPC; 1499e1833e1fSj_mayer break; 1500e1833e1fSj_mayer case POWERPC_EXCP_INVAL_LSWX: 1501e1833e1fSj_mayer info.si_code = TARGET_ILL_ILLOPN; 1502e1833e1fSj_mayer break; 1503e1833e1fSj_mayer case POWERPC_EXCP_INVAL_SPR: 1504e1833e1fSj_mayer info.si_code = TARGET_ILL_PRVREG; 1505e1833e1fSj_mayer break; 1506e1833e1fSj_mayer case POWERPC_EXCP_INVAL_FP: 1507e1833e1fSj_mayer info.si_code = TARGET_ILL_COPROC; 1508e1833e1fSj_mayer break; 1509e1833e1fSj_mayer default: 1510e1833e1fSj_mayer EXCP_DUMP(env, "Unknown invalid operation (%02x)\n", 1511e1833e1fSj_mayer env->error_code & 0xF); 1512e1833e1fSj_mayer info.si_code = TARGET_ILL_ILLADR; 1513e1833e1fSj_mayer break; 1514e1833e1fSj_mayer } 1515e1833e1fSj_mayer break; 1516e1833e1fSj_mayer case POWERPC_EXCP_PRIV: 1517e1833e1fSj_mayer EXCP_DUMP(env, "Privilege violation\n"); 1518e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1519e1833e1fSj_mayer info.si_errno = 0; 1520e1833e1fSj_mayer switch (env->error_code & 0xF) { 1521e1833e1fSj_mayer case POWERPC_EXCP_PRIV_OPC: 1522e1833e1fSj_mayer info.si_code = TARGET_ILL_PRVOPC; 1523e1833e1fSj_mayer break; 1524e1833e1fSj_mayer case POWERPC_EXCP_PRIV_REG: 1525e1833e1fSj_mayer info.si_code = TARGET_ILL_PRVREG; 1526e1833e1fSj_mayer break; 1527e1833e1fSj_mayer default: 1528e1833e1fSj_mayer EXCP_DUMP(env, "Unknown privilege violation (%02x)\n", 1529e1833e1fSj_mayer env->error_code & 0xF); 1530e1833e1fSj_mayer info.si_code = TARGET_ILL_PRVOPC; 1531e1833e1fSj_mayer break; 1532e1833e1fSj_mayer } 1533e1833e1fSj_mayer break; 1534e1833e1fSj_mayer case POWERPC_EXCP_TRAP: 1535e1833e1fSj_mayer cpu_abort(env, "Tried to call a TRAP\n"); 1536e1833e1fSj_mayer break; 1537e1833e1fSj_mayer default: 1538e1833e1fSj_mayer /* Should not happen ! */ 1539e1833e1fSj_mayer cpu_abort(env, "Unknown program exception (%02x)\n", 1540e1833e1fSj_mayer env->error_code); 1541e1833e1fSj_mayer break; 1542e1833e1fSj_mayer } 1543e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1544624f7979Spbrook queue_signal(env, info.si_signo, &info); 1545e1833e1fSj_mayer break; 1546e1833e1fSj_mayer case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ 1547e1833e1fSj_mayer EXCP_DUMP(env, "No floating point allowed\n"); 1548e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1549e1833e1fSj_mayer info.si_errno = 0; 1550e1833e1fSj_mayer info.si_code = TARGET_ILL_COPROC; 1551e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1552624f7979Spbrook queue_signal(env, info.si_signo, &info); 1553e1833e1fSj_mayer break; 1554e1833e1fSj_mayer case POWERPC_EXCP_SYSCALL: /* System call exception */ 1555e1833e1fSj_mayer cpu_abort(env, "Syscall exception while in user mode. " 1556e1833e1fSj_mayer "Aborting\n"); 1557e1833e1fSj_mayer break; 1558e1833e1fSj_mayer case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ 1559e1833e1fSj_mayer EXCP_DUMP(env, "No APU instruction allowed\n"); 1560e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1561e1833e1fSj_mayer info.si_errno = 0; 1562e1833e1fSj_mayer info.si_code = TARGET_ILL_COPROC; 1563e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1564624f7979Spbrook queue_signal(env, info.si_signo, &info); 1565e1833e1fSj_mayer break; 1566e1833e1fSj_mayer case POWERPC_EXCP_DECR: /* Decrementer exception */ 1567e1833e1fSj_mayer cpu_abort(env, "Decrementer interrupt while in user mode. " 1568e1833e1fSj_mayer "Aborting\n"); 1569e1833e1fSj_mayer break; 1570e1833e1fSj_mayer case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ 1571e1833e1fSj_mayer cpu_abort(env, "Fix interval timer interrupt while in user mode. " 1572e1833e1fSj_mayer "Aborting\n"); 1573e1833e1fSj_mayer break; 1574e1833e1fSj_mayer case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ 1575e1833e1fSj_mayer cpu_abort(env, "Watchdog timer interrupt while in user mode. " 1576e1833e1fSj_mayer "Aborting\n"); 1577e1833e1fSj_mayer break; 1578e1833e1fSj_mayer case POWERPC_EXCP_DTLB: /* Data TLB error */ 1579e1833e1fSj_mayer cpu_abort(env, "Data TLB exception while in user mode. " 1580e1833e1fSj_mayer "Aborting\n"); 1581e1833e1fSj_mayer break; 1582e1833e1fSj_mayer case POWERPC_EXCP_ITLB: /* Instruction TLB error */ 1583e1833e1fSj_mayer cpu_abort(env, "Instruction TLB exception while in user mode. " 1584e1833e1fSj_mayer "Aborting\n"); 1585e1833e1fSj_mayer break; 1586e1833e1fSj_mayer case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */ 1587e1833e1fSj_mayer EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n"); 1588e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1589e1833e1fSj_mayer info.si_errno = 0; 1590e1833e1fSj_mayer info.si_code = TARGET_ILL_COPROC; 1591e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1592624f7979Spbrook queue_signal(env, info.si_signo, &info); 1593e1833e1fSj_mayer break; 1594e1833e1fSj_mayer case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */ 1595e1833e1fSj_mayer cpu_abort(env, "Embedded floating-point data IRQ not handled\n"); 1596e1833e1fSj_mayer break; 1597e1833e1fSj_mayer case POWERPC_EXCP_EFPRI: /* Embedded floating-point round IRQ */ 1598e1833e1fSj_mayer cpu_abort(env, "Embedded floating-point round IRQ not handled\n"); 1599e1833e1fSj_mayer break; 1600e1833e1fSj_mayer case POWERPC_EXCP_EPERFM: /* Embedded performance monitor IRQ */ 1601e1833e1fSj_mayer cpu_abort(env, "Performance monitor exception not handled\n"); 1602e1833e1fSj_mayer break; 1603e1833e1fSj_mayer case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ 1604e1833e1fSj_mayer cpu_abort(env, "Doorbell interrupt while in user mode. " 1605e1833e1fSj_mayer "Aborting\n"); 1606e1833e1fSj_mayer break; 1607e1833e1fSj_mayer case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ 1608e1833e1fSj_mayer cpu_abort(env, "Doorbell critical interrupt while in user mode. " 1609e1833e1fSj_mayer "Aborting\n"); 1610e1833e1fSj_mayer break; 1611e1833e1fSj_mayer case POWERPC_EXCP_RESET: /* System reset exception */ 1612e1833e1fSj_mayer cpu_abort(env, "Reset interrupt while in user mode. " 1613e1833e1fSj_mayer "Aborting\n"); 1614e1833e1fSj_mayer break; 1615e1833e1fSj_mayer case POWERPC_EXCP_DSEG: /* Data segment exception */ 1616e1833e1fSj_mayer cpu_abort(env, "Data segment exception while in user mode. " 1617e1833e1fSj_mayer "Aborting\n"); 1618e1833e1fSj_mayer break; 1619e1833e1fSj_mayer case POWERPC_EXCP_ISEG: /* Instruction segment exception */ 1620e1833e1fSj_mayer cpu_abort(env, "Instruction segment exception " 1621e1833e1fSj_mayer "while in user mode. Aborting\n"); 1622e1833e1fSj_mayer break; 1623e85e7c6eSj_mayer /* PowerPC 64 with hypervisor mode support */ 1624e1833e1fSj_mayer case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ 1625e1833e1fSj_mayer cpu_abort(env, "Hypervisor decrementer interrupt " 1626e1833e1fSj_mayer "while in user mode. Aborting\n"); 1627e1833e1fSj_mayer break; 1628e1833e1fSj_mayer case POWERPC_EXCP_TRACE: /* Trace exception */ 1629e1833e1fSj_mayer /* Nothing to do: 1630e1833e1fSj_mayer * we use this exception to emulate step-by-step execution mode. 1631e1833e1fSj_mayer */ 1632e1833e1fSj_mayer break; 1633e85e7c6eSj_mayer /* PowerPC 64 with hypervisor mode support */ 1634e1833e1fSj_mayer case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ 1635e1833e1fSj_mayer cpu_abort(env, "Hypervisor data storage exception " 1636e1833e1fSj_mayer "while in user mode. Aborting\n"); 1637e1833e1fSj_mayer break; 1638e1833e1fSj_mayer case POWERPC_EXCP_HISI: /* Hypervisor instruction storage excp */ 1639e1833e1fSj_mayer cpu_abort(env, "Hypervisor instruction storage exception " 1640e1833e1fSj_mayer "while in user mode. Aborting\n"); 1641e1833e1fSj_mayer break; 1642e1833e1fSj_mayer case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ 1643e1833e1fSj_mayer cpu_abort(env, "Hypervisor data segment exception " 1644e1833e1fSj_mayer "while in user mode. Aborting\n"); 1645e1833e1fSj_mayer break; 1646e1833e1fSj_mayer case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment excp */ 1647e1833e1fSj_mayer cpu_abort(env, "Hypervisor instruction segment exception " 1648e1833e1fSj_mayer "while in user mode. Aborting\n"); 1649e1833e1fSj_mayer break; 1650e1833e1fSj_mayer case POWERPC_EXCP_VPU: /* Vector unavailable exception */ 1651e1833e1fSj_mayer EXCP_DUMP(env, "No Altivec instructions allowed\n"); 1652e1833e1fSj_mayer info.si_signo = TARGET_SIGILL; 1653e1833e1fSj_mayer info.si_errno = 0; 1654e1833e1fSj_mayer info.si_code = TARGET_ILL_COPROC; 1655e1833e1fSj_mayer info._sifields._sigfault._addr = env->nip - 4; 1656624f7979Spbrook queue_signal(env, info.si_signo, &info); 1657e1833e1fSj_mayer break; 1658e1833e1fSj_mayer case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */ 1659b4916d7bSDong Xu Wang cpu_abort(env, "Programmable interval timer interrupt " 1660e1833e1fSj_mayer "while in user mode. Aborting\n"); 1661e1833e1fSj_mayer break; 1662e1833e1fSj_mayer case POWERPC_EXCP_IO: /* IO error exception */ 1663e1833e1fSj_mayer cpu_abort(env, "IO error exception while in user mode. " 1664e1833e1fSj_mayer "Aborting\n"); 1665e1833e1fSj_mayer break; 1666e1833e1fSj_mayer case POWERPC_EXCP_RUNM: /* Run mode exception */ 1667e1833e1fSj_mayer cpu_abort(env, "Run mode exception while in user mode. " 1668e1833e1fSj_mayer "Aborting\n"); 1669e1833e1fSj_mayer break; 1670e1833e1fSj_mayer case POWERPC_EXCP_EMUL: /* Emulation trap exception */ 1671e1833e1fSj_mayer cpu_abort(env, "Emulation trap exception not handled\n"); 1672e1833e1fSj_mayer break; 1673e1833e1fSj_mayer case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ 1674e1833e1fSj_mayer cpu_abort(env, "Instruction fetch TLB exception " 1675e1833e1fSj_mayer "while in user-mode. Aborting"); 1676e1833e1fSj_mayer break; 1677e1833e1fSj_mayer case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ 1678e1833e1fSj_mayer cpu_abort(env, "Data load TLB exception while in user-mode. " 1679e1833e1fSj_mayer "Aborting"); 1680e1833e1fSj_mayer break; 1681e1833e1fSj_mayer case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ 1682e1833e1fSj_mayer cpu_abort(env, "Data store TLB exception while in user-mode. " 1683e1833e1fSj_mayer "Aborting"); 1684e1833e1fSj_mayer break; 1685e1833e1fSj_mayer case POWERPC_EXCP_FPA: /* Floating-point assist exception */ 1686e1833e1fSj_mayer cpu_abort(env, "Floating-point assist exception not handled\n"); 1687e1833e1fSj_mayer break; 1688e1833e1fSj_mayer case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ 1689e1833e1fSj_mayer cpu_abort(env, "Instruction address breakpoint exception " 1690e1833e1fSj_mayer "not handled\n"); 1691e1833e1fSj_mayer break; 1692e1833e1fSj_mayer case POWERPC_EXCP_SMI: /* System management interrupt */ 1693e1833e1fSj_mayer cpu_abort(env, "System management interrupt while in user mode. " 1694e1833e1fSj_mayer "Aborting\n"); 1695e1833e1fSj_mayer break; 1696e1833e1fSj_mayer case POWERPC_EXCP_THERM: /* Thermal interrupt */ 1697e1833e1fSj_mayer cpu_abort(env, "Thermal interrupt interrupt while in user mode. " 1698e1833e1fSj_mayer "Aborting\n"); 1699e1833e1fSj_mayer break; 1700e1833e1fSj_mayer case POWERPC_EXCP_PERFM: /* Embedded performance monitor IRQ */ 1701e1833e1fSj_mayer cpu_abort(env, "Performance monitor exception not handled\n"); 1702e1833e1fSj_mayer break; 1703e1833e1fSj_mayer case POWERPC_EXCP_VPUA: /* Vector assist exception */ 1704e1833e1fSj_mayer cpu_abort(env, "Vector assist exception not handled\n"); 1705e1833e1fSj_mayer break; 1706e1833e1fSj_mayer case POWERPC_EXCP_SOFTP: /* Soft patch exception */ 1707e1833e1fSj_mayer cpu_abort(env, "Soft patch exception not handled\n"); 1708e1833e1fSj_mayer break; 1709e1833e1fSj_mayer case POWERPC_EXCP_MAINT: /* Maintenance exception */ 1710e1833e1fSj_mayer cpu_abort(env, "Maintenance exception while in user mode. " 1711e1833e1fSj_mayer "Aborting\n"); 1712e1833e1fSj_mayer break; 1713e1833e1fSj_mayer case POWERPC_EXCP_STOP: /* stop translation */ 1714e1833e1fSj_mayer /* We did invalidate the instruction cache. Go on */ 1715e1833e1fSj_mayer break; 1716e1833e1fSj_mayer case POWERPC_EXCP_BRANCH: /* branch instruction: */ 1717e1833e1fSj_mayer /* We just stopped because of a branch. Go on */ 1718e1833e1fSj_mayer break; 1719e1833e1fSj_mayer case POWERPC_EXCP_SYSCALL_USER: 1720e1833e1fSj_mayer /* system call in user-mode emulation */ 172167867308Sbellard /* WARNING: 172267867308Sbellard * PPC ABI uses overflow flag in cr0 to signal an error 172367867308Sbellard * in syscalls. 172467867308Sbellard */ 172567867308Sbellard env->crf[0] &= ~0x1; 172667867308Sbellard ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], 172767867308Sbellard env->gpr[5], env->gpr[6], env->gpr[7], 17285945cfcbSPeter Maydell env->gpr[8], 0, 0); 17299e0e2f96SRichard Henderson if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { 1730bcd4933aSNathan Froyd /* Returning from a successful sigreturn syscall. 1731bcd4933aSNathan Froyd Avoid corrupting register state. */ 1732bcd4933aSNathan Froyd break; 1733bcd4933aSNathan Froyd } 17349e0e2f96SRichard Henderson if (ret > (target_ulong)(-515)) { 173567867308Sbellard env->crf[0] |= 0x1; 173667867308Sbellard ret = -ret; 173767867308Sbellard } 173867867308Sbellard env->gpr[3] = ret; 173961190b14Sbellard break; 174056f066bbSNathan Froyd case POWERPC_EXCP_STCX: 174156f066bbSNathan Froyd if (do_store_exclusive(env)) { 174256f066bbSNathan Froyd info.si_signo = TARGET_SIGSEGV; 174356f066bbSNathan Froyd info.si_errno = 0; 174456f066bbSNathan Froyd info.si_code = TARGET_SEGV_MAPERR; 174556f066bbSNathan Froyd info._sifields._sigfault._addr = env->nip; 174656f066bbSNathan Froyd queue_signal(env, info.si_signo, &info); 174756f066bbSNathan Froyd } 174856f066bbSNathan Froyd break; 174971f75756Saurel32 case EXCP_DEBUG: 175071f75756Saurel32 { 175171f75756Saurel32 int sig; 175271f75756Saurel32 175371f75756Saurel32 sig = gdb_handlesig(env, TARGET_SIGTRAP); 175471f75756Saurel32 if (sig) { 175571f75756Saurel32 info.si_signo = sig; 175671f75756Saurel32 info.si_errno = 0; 175771f75756Saurel32 info.si_code = TARGET_TRAP_BRKPT; 175871f75756Saurel32 queue_signal(env, info.si_signo, &info); 175971f75756Saurel32 } 176071f75756Saurel32 } 176171f75756Saurel32 break; 176256ba31ffSj_mayer case EXCP_INTERRUPT: 176356ba31ffSj_mayer /* just indicate that signals should be handled asap */ 176456ba31ffSj_mayer break; 176561190b14Sbellard default: 1766e1833e1fSj_mayer cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr); 176767867308Sbellard break; 176867867308Sbellard } 176967867308Sbellard process_pending_signals(env); 177067867308Sbellard } 177167867308Sbellard } 177267867308Sbellard #endif 177367867308Sbellard 1774048f6b4dSbellard #ifdef TARGET_MIPS 1775048f6b4dSbellard 1776048f6b4dSbellard #define MIPS_SYS(name, args) args, 1777048f6b4dSbellard 1778048f6b4dSbellard static const uint8_t mips_syscall_args[] = { 177929fb0f25SAn-Cheng Huang MIPS_SYS(sys_syscall , 8) /* 4000 */ 1780048f6b4dSbellard MIPS_SYS(sys_exit , 1) 1781048f6b4dSbellard MIPS_SYS(sys_fork , 0) 1782048f6b4dSbellard MIPS_SYS(sys_read , 3) 1783048f6b4dSbellard MIPS_SYS(sys_write , 3) 1784048f6b4dSbellard MIPS_SYS(sys_open , 3) /* 4005 */ 1785048f6b4dSbellard MIPS_SYS(sys_close , 1) 1786048f6b4dSbellard MIPS_SYS(sys_waitpid , 3) 1787048f6b4dSbellard MIPS_SYS(sys_creat , 2) 1788048f6b4dSbellard MIPS_SYS(sys_link , 2) 1789048f6b4dSbellard MIPS_SYS(sys_unlink , 1) /* 4010 */ 1790048f6b4dSbellard MIPS_SYS(sys_execve , 0) 1791048f6b4dSbellard MIPS_SYS(sys_chdir , 1) 1792048f6b4dSbellard MIPS_SYS(sys_time , 1) 1793048f6b4dSbellard MIPS_SYS(sys_mknod , 3) 1794048f6b4dSbellard MIPS_SYS(sys_chmod , 2) /* 4015 */ 1795048f6b4dSbellard MIPS_SYS(sys_lchown , 3) 1796048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1797048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was sys_stat */ 1798048f6b4dSbellard MIPS_SYS(sys_lseek , 3) 1799048f6b4dSbellard MIPS_SYS(sys_getpid , 0) /* 4020 */ 1800048f6b4dSbellard MIPS_SYS(sys_mount , 5) 1801048f6b4dSbellard MIPS_SYS(sys_oldumount , 1) 1802048f6b4dSbellard MIPS_SYS(sys_setuid , 1) 1803048f6b4dSbellard MIPS_SYS(sys_getuid , 0) 1804048f6b4dSbellard MIPS_SYS(sys_stime , 1) /* 4025 */ 1805048f6b4dSbellard MIPS_SYS(sys_ptrace , 4) 1806048f6b4dSbellard MIPS_SYS(sys_alarm , 1) 1807048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was sys_fstat */ 1808048f6b4dSbellard MIPS_SYS(sys_pause , 0) 1809048f6b4dSbellard MIPS_SYS(sys_utime , 2) /* 4030 */ 1810048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1811048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1812048f6b4dSbellard MIPS_SYS(sys_access , 2) 1813048f6b4dSbellard MIPS_SYS(sys_nice , 1) 1814048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* 4035 */ 1815048f6b4dSbellard MIPS_SYS(sys_sync , 0) 1816048f6b4dSbellard MIPS_SYS(sys_kill , 2) 1817048f6b4dSbellard MIPS_SYS(sys_rename , 2) 1818048f6b4dSbellard MIPS_SYS(sys_mkdir , 2) 1819048f6b4dSbellard MIPS_SYS(sys_rmdir , 1) /* 4040 */ 1820048f6b4dSbellard MIPS_SYS(sys_dup , 1) 1821048f6b4dSbellard MIPS_SYS(sys_pipe , 0) 1822048f6b4dSbellard MIPS_SYS(sys_times , 1) 1823048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1824048f6b4dSbellard MIPS_SYS(sys_brk , 1) /* 4045 */ 1825048f6b4dSbellard MIPS_SYS(sys_setgid , 1) 1826048f6b4dSbellard MIPS_SYS(sys_getgid , 0) 1827048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was signal(2) */ 1828048f6b4dSbellard MIPS_SYS(sys_geteuid , 0) 1829048f6b4dSbellard MIPS_SYS(sys_getegid , 0) /* 4050 */ 1830048f6b4dSbellard MIPS_SYS(sys_acct , 0) 1831048f6b4dSbellard MIPS_SYS(sys_umount , 2) 1832048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1833048f6b4dSbellard MIPS_SYS(sys_ioctl , 3) 1834048f6b4dSbellard MIPS_SYS(sys_fcntl , 3) /* 4055 */ 1835048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 2) 1836048f6b4dSbellard MIPS_SYS(sys_setpgid , 2) 1837048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1838048f6b4dSbellard MIPS_SYS(sys_olduname , 1) 1839048f6b4dSbellard MIPS_SYS(sys_umask , 1) /* 4060 */ 1840048f6b4dSbellard MIPS_SYS(sys_chroot , 1) 1841048f6b4dSbellard MIPS_SYS(sys_ustat , 2) 1842048f6b4dSbellard MIPS_SYS(sys_dup2 , 2) 1843048f6b4dSbellard MIPS_SYS(sys_getppid , 0) 1844048f6b4dSbellard MIPS_SYS(sys_getpgrp , 0) /* 4065 */ 1845048f6b4dSbellard MIPS_SYS(sys_setsid , 0) 1846048f6b4dSbellard MIPS_SYS(sys_sigaction , 3) 1847048f6b4dSbellard MIPS_SYS(sys_sgetmask , 0) 1848048f6b4dSbellard MIPS_SYS(sys_ssetmask , 1) 1849048f6b4dSbellard MIPS_SYS(sys_setreuid , 2) /* 4070 */ 1850048f6b4dSbellard MIPS_SYS(sys_setregid , 2) 1851048f6b4dSbellard MIPS_SYS(sys_sigsuspend , 0) 1852048f6b4dSbellard MIPS_SYS(sys_sigpending , 1) 1853048f6b4dSbellard MIPS_SYS(sys_sethostname , 2) 1854048f6b4dSbellard MIPS_SYS(sys_setrlimit , 2) /* 4075 */ 1855048f6b4dSbellard MIPS_SYS(sys_getrlimit , 2) 1856048f6b4dSbellard MIPS_SYS(sys_getrusage , 2) 1857048f6b4dSbellard MIPS_SYS(sys_gettimeofday, 2) 1858048f6b4dSbellard MIPS_SYS(sys_settimeofday, 2) 1859048f6b4dSbellard MIPS_SYS(sys_getgroups , 2) /* 4080 */ 1860048f6b4dSbellard MIPS_SYS(sys_setgroups , 2) 1861048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* old_select */ 1862048f6b4dSbellard MIPS_SYS(sys_symlink , 2) 1863048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was sys_lstat */ 1864048f6b4dSbellard MIPS_SYS(sys_readlink , 3) /* 4085 */ 1865048f6b4dSbellard MIPS_SYS(sys_uselib , 1) 1866048f6b4dSbellard MIPS_SYS(sys_swapon , 2) 1867048f6b4dSbellard MIPS_SYS(sys_reboot , 3) 1868048f6b4dSbellard MIPS_SYS(old_readdir , 3) 1869048f6b4dSbellard MIPS_SYS(old_mmap , 6) /* 4090 */ 1870048f6b4dSbellard MIPS_SYS(sys_munmap , 2) 1871048f6b4dSbellard MIPS_SYS(sys_truncate , 2) 1872048f6b4dSbellard MIPS_SYS(sys_ftruncate , 2) 1873048f6b4dSbellard MIPS_SYS(sys_fchmod , 2) 1874048f6b4dSbellard MIPS_SYS(sys_fchown , 3) /* 4095 */ 1875048f6b4dSbellard MIPS_SYS(sys_getpriority , 2) 1876048f6b4dSbellard MIPS_SYS(sys_setpriority , 3) 1877048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1878048f6b4dSbellard MIPS_SYS(sys_statfs , 2) 1879048f6b4dSbellard MIPS_SYS(sys_fstatfs , 2) /* 4100 */ 1880048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was ioperm(2) */ 1881048f6b4dSbellard MIPS_SYS(sys_socketcall , 2) 1882048f6b4dSbellard MIPS_SYS(sys_syslog , 3) 1883048f6b4dSbellard MIPS_SYS(sys_setitimer , 3) 1884048f6b4dSbellard MIPS_SYS(sys_getitimer , 2) /* 4105 */ 1885048f6b4dSbellard MIPS_SYS(sys_newstat , 2) 1886048f6b4dSbellard MIPS_SYS(sys_newlstat , 2) 1887048f6b4dSbellard MIPS_SYS(sys_newfstat , 2) 1888048f6b4dSbellard MIPS_SYS(sys_uname , 1) 1889048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* 4110 was iopl(2) */ 1890048f6b4dSbellard MIPS_SYS(sys_vhangup , 0) 1891048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was sys_idle() */ 1892048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was sys_vm86 */ 1893048f6b4dSbellard MIPS_SYS(sys_wait4 , 4) 1894048f6b4dSbellard MIPS_SYS(sys_swapoff , 1) /* 4115 */ 1895048f6b4dSbellard MIPS_SYS(sys_sysinfo , 1) 1896048f6b4dSbellard MIPS_SYS(sys_ipc , 6) 1897048f6b4dSbellard MIPS_SYS(sys_fsync , 1) 1898048f6b4dSbellard MIPS_SYS(sys_sigreturn , 0) 189918113962SPaul Brook MIPS_SYS(sys_clone , 6) /* 4120 */ 1900048f6b4dSbellard MIPS_SYS(sys_setdomainname, 2) 1901048f6b4dSbellard MIPS_SYS(sys_newuname , 1) 1902048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */ 1903048f6b4dSbellard MIPS_SYS(sys_adjtimex , 1) 1904048f6b4dSbellard MIPS_SYS(sys_mprotect , 3) /* 4125 */ 1905048f6b4dSbellard MIPS_SYS(sys_sigprocmask , 3) 1906048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was create_module */ 1907048f6b4dSbellard MIPS_SYS(sys_init_module , 5) 1908048f6b4dSbellard MIPS_SYS(sys_delete_module, 1) 1909048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* 4130 was get_kernel_syms */ 1910048f6b4dSbellard MIPS_SYS(sys_quotactl , 0) 1911048f6b4dSbellard MIPS_SYS(sys_getpgid , 1) 1912048f6b4dSbellard MIPS_SYS(sys_fchdir , 1) 1913048f6b4dSbellard MIPS_SYS(sys_bdflush , 2) 1914048f6b4dSbellard MIPS_SYS(sys_sysfs , 3) /* 4135 */ 1915048f6b4dSbellard MIPS_SYS(sys_personality , 1) 1916048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* for afs_syscall */ 1917048f6b4dSbellard MIPS_SYS(sys_setfsuid , 1) 1918048f6b4dSbellard MIPS_SYS(sys_setfsgid , 1) 1919048f6b4dSbellard MIPS_SYS(sys_llseek , 5) /* 4140 */ 1920048f6b4dSbellard MIPS_SYS(sys_getdents , 3) 1921048f6b4dSbellard MIPS_SYS(sys_select , 5) 1922048f6b4dSbellard MIPS_SYS(sys_flock , 2) 1923048f6b4dSbellard MIPS_SYS(sys_msync , 3) 1924048f6b4dSbellard MIPS_SYS(sys_readv , 3) /* 4145 */ 1925048f6b4dSbellard MIPS_SYS(sys_writev , 3) 1926048f6b4dSbellard MIPS_SYS(sys_cacheflush , 3) 1927048f6b4dSbellard MIPS_SYS(sys_cachectl , 3) 1928048f6b4dSbellard MIPS_SYS(sys_sysmips , 4) 1929048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* 4150 */ 1930048f6b4dSbellard MIPS_SYS(sys_getsid , 1) 1931048f6b4dSbellard MIPS_SYS(sys_fdatasync , 0) 1932048f6b4dSbellard MIPS_SYS(sys_sysctl , 1) 1933048f6b4dSbellard MIPS_SYS(sys_mlock , 2) 1934048f6b4dSbellard MIPS_SYS(sys_munlock , 2) /* 4155 */ 1935048f6b4dSbellard MIPS_SYS(sys_mlockall , 1) 1936048f6b4dSbellard MIPS_SYS(sys_munlockall , 0) 1937048f6b4dSbellard MIPS_SYS(sys_sched_setparam, 2) 1938048f6b4dSbellard MIPS_SYS(sys_sched_getparam, 2) 1939048f6b4dSbellard MIPS_SYS(sys_sched_setscheduler, 3) /* 4160 */ 1940048f6b4dSbellard MIPS_SYS(sys_sched_getscheduler, 1) 1941048f6b4dSbellard MIPS_SYS(sys_sched_yield , 0) 1942048f6b4dSbellard MIPS_SYS(sys_sched_get_priority_max, 1) 1943048f6b4dSbellard MIPS_SYS(sys_sched_get_priority_min, 1) 1944048f6b4dSbellard MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */ 1945048f6b4dSbellard MIPS_SYS(sys_nanosleep, 2) 1946048f6b4dSbellard MIPS_SYS(sys_mremap , 4) 1947048f6b4dSbellard MIPS_SYS(sys_accept , 3) 1948048f6b4dSbellard MIPS_SYS(sys_bind , 3) 1949048f6b4dSbellard MIPS_SYS(sys_connect , 3) /* 4170 */ 1950048f6b4dSbellard MIPS_SYS(sys_getpeername , 3) 1951048f6b4dSbellard MIPS_SYS(sys_getsockname , 3) 1952048f6b4dSbellard MIPS_SYS(sys_getsockopt , 5) 1953048f6b4dSbellard MIPS_SYS(sys_listen , 2) 1954048f6b4dSbellard MIPS_SYS(sys_recv , 4) /* 4175 */ 1955048f6b4dSbellard MIPS_SYS(sys_recvfrom , 6) 1956048f6b4dSbellard MIPS_SYS(sys_recvmsg , 3) 1957048f6b4dSbellard MIPS_SYS(sys_send , 4) 1958048f6b4dSbellard MIPS_SYS(sys_sendmsg , 3) 1959048f6b4dSbellard MIPS_SYS(sys_sendto , 6) /* 4180 */ 1960048f6b4dSbellard MIPS_SYS(sys_setsockopt , 5) 1961048f6b4dSbellard MIPS_SYS(sys_shutdown , 2) 1962048f6b4dSbellard MIPS_SYS(sys_socket , 3) 1963048f6b4dSbellard MIPS_SYS(sys_socketpair , 4) 1964048f6b4dSbellard MIPS_SYS(sys_setresuid , 3) /* 4185 */ 1965048f6b4dSbellard MIPS_SYS(sys_getresuid , 3) 1966048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* was sys_query_module */ 1967048f6b4dSbellard MIPS_SYS(sys_poll , 3) 1968048f6b4dSbellard MIPS_SYS(sys_nfsservctl , 3) 1969048f6b4dSbellard MIPS_SYS(sys_setresgid , 3) /* 4190 */ 1970048f6b4dSbellard MIPS_SYS(sys_getresgid , 3) 1971048f6b4dSbellard MIPS_SYS(sys_prctl , 5) 1972048f6b4dSbellard MIPS_SYS(sys_rt_sigreturn, 0) 1973048f6b4dSbellard MIPS_SYS(sys_rt_sigaction, 4) 1974048f6b4dSbellard MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */ 1975048f6b4dSbellard MIPS_SYS(sys_rt_sigpending, 2) 1976048f6b4dSbellard MIPS_SYS(sys_rt_sigtimedwait, 4) 1977048f6b4dSbellard MIPS_SYS(sys_rt_sigqueueinfo, 3) 1978048f6b4dSbellard MIPS_SYS(sys_rt_sigsuspend, 0) 1979048f6b4dSbellard MIPS_SYS(sys_pread64 , 6) /* 4200 */ 1980048f6b4dSbellard MIPS_SYS(sys_pwrite64 , 6) 1981048f6b4dSbellard MIPS_SYS(sys_chown , 3) 1982048f6b4dSbellard MIPS_SYS(sys_getcwd , 2) 1983048f6b4dSbellard MIPS_SYS(sys_capget , 2) 1984048f6b4dSbellard MIPS_SYS(sys_capset , 2) /* 4205 */ 1985053ebb27SWesley W. Terpstra MIPS_SYS(sys_sigaltstack , 2) 1986048f6b4dSbellard MIPS_SYS(sys_sendfile , 4) 1987048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1988048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 1989048f6b4dSbellard MIPS_SYS(sys_mmap2 , 6) /* 4210 */ 1990048f6b4dSbellard MIPS_SYS(sys_truncate64 , 4) 1991048f6b4dSbellard MIPS_SYS(sys_ftruncate64 , 4) 1992048f6b4dSbellard MIPS_SYS(sys_stat64 , 2) 1993048f6b4dSbellard MIPS_SYS(sys_lstat64 , 2) 1994048f6b4dSbellard MIPS_SYS(sys_fstat64 , 2) /* 4215 */ 1995048f6b4dSbellard MIPS_SYS(sys_pivot_root , 2) 1996048f6b4dSbellard MIPS_SYS(sys_mincore , 3) 1997048f6b4dSbellard MIPS_SYS(sys_madvise , 3) 1998048f6b4dSbellard MIPS_SYS(sys_getdents64 , 3) 1999048f6b4dSbellard MIPS_SYS(sys_fcntl64 , 3) /* 4220 */ 2000048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) 2001048f6b4dSbellard MIPS_SYS(sys_gettid , 0) 2002048f6b4dSbellard MIPS_SYS(sys_readahead , 5) 2003048f6b4dSbellard MIPS_SYS(sys_setxattr , 5) 2004048f6b4dSbellard MIPS_SYS(sys_lsetxattr , 5) /* 4225 */ 2005048f6b4dSbellard MIPS_SYS(sys_fsetxattr , 5) 2006048f6b4dSbellard MIPS_SYS(sys_getxattr , 4) 2007048f6b4dSbellard MIPS_SYS(sys_lgetxattr , 4) 2008048f6b4dSbellard MIPS_SYS(sys_fgetxattr , 4) 2009048f6b4dSbellard MIPS_SYS(sys_listxattr , 3) /* 4230 */ 2010048f6b4dSbellard MIPS_SYS(sys_llistxattr , 3) 2011048f6b4dSbellard MIPS_SYS(sys_flistxattr , 3) 2012048f6b4dSbellard MIPS_SYS(sys_removexattr , 2) 2013048f6b4dSbellard MIPS_SYS(sys_lremovexattr, 2) 2014048f6b4dSbellard MIPS_SYS(sys_fremovexattr, 2) /* 4235 */ 2015048f6b4dSbellard MIPS_SYS(sys_tkill , 2) 2016048f6b4dSbellard MIPS_SYS(sys_sendfile64 , 5) 2017048f6b4dSbellard MIPS_SYS(sys_futex , 2) 2018048f6b4dSbellard MIPS_SYS(sys_sched_setaffinity, 3) 2019048f6b4dSbellard MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */ 2020048f6b4dSbellard MIPS_SYS(sys_io_setup , 2) 2021048f6b4dSbellard MIPS_SYS(sys_io_destroy , 1) 2022048f6b4dSbellard MIPS_SYS(sys_io_getevents, 5) 2023048f6b4dSbellard MIPS_SYS(sys_io_submit , 3) 2024048f6b4dSbellard MIPS_SYS(sys_io_cancel , 3) /* 4245 */ 2025048f6b4dSbellard MIPS_SYS(sys_exit_group , 1) 2026048f6b4dSbellard MIPS_SYS(sys_lookup_dcookie, 3) 2027048f6b4dSbellard MIPS_SYS(sys_epoll_create, 1) 2028048f6b4dSbellard MIPS_SYS(sys_epoll_ctl , 4) 2029048f6b4dSbellard MIPS_SYS(sys_epoll_wait , 3) /* 4250 */ 2030048f6b4dSbellard MIPS_SYS(sys_remap_file_pages, 5) 2031048f6b4dSbellard MIPS_SYS(sys_set_tid_address, 1) 2032048f6b4dSbellard MIPS_SYS(sys_restart_syscall, 0) 2033048f6b4dSbellard MIPS_SYS(sys_fadvise64_64, 7) 2034048f6b4dSbellard MIPS_SYS(sys_statfs64 , 3) /* 4255 */ 2035048f6b4dSbellard MIPS_SYS(sys_fstatfs64 , 2) 2036048f6b4dSbellard MIPS_SYS(sys_timer_create, 3) 2037048f6b4dSbellard MIPS_SYS(sys_timer_settime, 4) 2038048f6b4dSbellard MIPS_SYS(sys_timer_gettime, 2) 2039048f6b4dSbellard MIPS_SYS(sys_timer_getoverrun, 1) /* 4260 */ 2040048f6b4dSbellard MIPS_SYS(sys_timer_delete, 1) 2041048f6b4dSbellard MIPS_SYS(sys_clock_settime, 2) 2042048f6b4dSbellard MIPS_SYS(sys_clock_gettime, 2) 2043048f6b4dSbellard MIPS_SYS(sys_clock_getres, 2) 2044048f6b4dSbellard MIPS_SYS(sys_clock_nanosleep, 4) /* 4265 */ 2045048f6b4dSbellard MIPS_SYS(sys_tgkill , 3) 2046048f6b4dSbellard MIPS_SYS(sys_utimes , 2) 2047048f6b4dSbellard MIPS_SYS(sys_mbind , 4) 2048048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* sys_get_mempolicy */ 2049048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* 4270 sys_set_mempolicy */ 2050048f6b4dSbellard MIPS_SYS(sys_mq_open , 4) 2051048f6b4dSbellard MIPS_SYS(sys_mq_unlink , 1) 2052048f6b4dSbellard MIPS_SYS(sys_mq_timedsend, 5) 2053048f6b4dSbellard MIPS_SYS(sys_mq_timedreceive, 5) 2054048f6b4dSbellard MIPS_SYS(sys_mq_notify , 2) /* 4275 */ 2055048f6b4dSbellard MIPS_SYS(sys_mq_getsetattr, 3) 2056048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* sys_vserver */ 2057048f6b4dSbellard MIPS_SYS(sys_waitid , 4) 2058048f6b4dSbellard MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */ 2059048f6b4dSbellard MIPS_SYS(sys_add_key , 5) 2060048f6b4dSbellard MIPS_SYS(sys_request_key, 4) 2061048f6b4dSbellard MIPS_SYS(sys_keyctl , 5) 20626f5b89a0Sths MIPS_SYS(sys_set_thread_area, 1) 2063388bb21aSths MIPS_SYS(sys_inotify_init, 0) 2064388bb21aSths MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */ 2065388bb21aSths MIPS_SYS(sys_inotify_rm_watch, 2) 2066388bb21aSths MIPS_SYS(sys_migrate_pages, 4) 2067388bb21aSths MIPS_SYS(sys_openat, 4) 2068388bb21aSths MIPS_SYS(sys_mkdirat, 3) 2069388bb21aSths MIPS_SYS(sys_mknodat, 4) /* 4290 */ 2070388bb21aSths MIPS_SYS(sys_fchownat, 5) 2071388bb21aSths MIPS_SYS(sys_futimesat, 3) 2072388bb21aSths MIPS_SYS(sys_fstatat64, 4) 2073388bb21aSths MIPS_SYS(sys_unlinkat, 3) 2074388bb21aSths MIPS_SYS(sys_renameat, 4) /* 4295 */ 2075388bb21aSths MIPS_SYS(sys_linkat, 5) 2076388bb21aSths MIPS_SYS(sys_symlinkat, 3) 2077388bb21aSths MIPS_SYS(sys_readlinkat, 4) 2078388bb21aSths MIPS_SYS(sys_fchmodat, 3) 2079388bb21aSths MIPS_SYS(sys_faccessat, 3) /* 4300 */ 2080388bb21aSths MIPS_SYS(sys_pselect6, 6) 2081388bb21aSths MIPS_SYS(sys_ppoll, 5) 2082388bb21aSths MIPS_SYS(sys_unshare, 1) 2083388bb21aSths MIPS_SYS(sys_splice, 4) 2084388bb21aSths MIPS_SYS(sys_sync_file_range, 7) /* 4305 */ 2085388bb21aSths MIPS_SYS(sys_tee, 4) 2086388bb21aSths MIPS_SYS(sys_vmsplice, 4) 2087388bb21aSths MIPS_SYS(sys_move_pages, 6) 2088388bb21aSths MIPS_SYS(sys_set_robust_list, 2) 2089388bb21aSths MIPS_SYS(sys_get_robust_list, 3) /* 4310 */ 2090388bb21aSths MIPS_SYS(sys_kexec_load, 4) 2091388bb21aSths MIPS_SYS(sys_getcpu, 3) 2092388bb21aSths MIPS_SYS(sys_epoll_pwait, 6) 2093388bb21aSths MIPS_SYS(sys_ioprio_set, 3) 2094388bb21aSths MIPS_SYS(sys_ioprio_get, 2) 2095d979e8ebSPeter Maydell MIPS_SYS(sys_utimensat, 4) 2096d979e8ebSPeter Maydell MIPS_SYS(sys_signalfd, 3) 2097d979e8ebSPeter Maydell MIPS_SYS(sys_ni_syscall, 0) /* was timerfd */ 2098d979e8ebSPeter Maydell MIPS_SYS(sys_eventfd, 1) 2099d979e8ebSPeter Maydell MIPS_SYS(sys_fallocate, 6) /* 4320 */ 2100d979e8ebSPeter Maydell MIPS_SYS(sys_timerfd_create, 2) 2101d979e8ebSPeter Maydell MIPS_SYS(sys_timerfd_gettime, 2) 2102d979e8ebSPeter Maydell MIPS_SYS(sys_timerfd_settime, 4) 2103d979e8ebSPeter Maydell MIPS_SYS(sys_signalfd4, 4) 2104d979e8ebSPeter Maydell MIPS_SYS(sys_eventfd2, 2) /* 4325 */ 2105d979e8ebSPeter Maydell MIPS_SYS(sys_epoll_create1, 1) 2106d979e8ebSPeter Maydell MIPS_SYS(sys_dup3, 3) 2107d979e8ebSPeter Maydell MIPS_SYS(sys_pipe2, 2) 2108d979e8ebSPeter Maydell MIPS_SYS(sys_inotify_init1, 1) 2109d979e8ebSPeter Maydell MIPS_SYS(sys_preadv, 6) /* 4330 */ 2110d979e8ebSPeter Maydell MIPS_SYS(sys_pwritev, 6) 2111d979e8ebSPeter Maydell MIPS_SYS(sys_rt_tgsigqueueinfo, 4) 2112d979e8ebSPeter Maydell MIPS_SYS(sys_perf_event_open, 5) 2113d979e8ebSPeter Maydell MIPS_SYS(sys_accept4, 4) 2114d979e8ebSPeter Maydell MIPS_SYS(sys_recvmmsg, 5) /* 4335 */ 2115d979e8ebSPeter Maydell MIPS_SYS(sys_fanotify_init, 2) 2116d979e8ebSPeter Maydell MIPS_SYS(sys_fanotify_mark, 6) 2117d979e8ebSPeter Maydell MIPS_SYS(sys_prlimit64, 4) 2118d979e8ebSPeter Maydell MIPS_SYS(sys_name_to_handle_at, 5) 2119d979e8ebSPeter Maydell MIPS_SYS(sys_open_by_handle_at, 3) /* 4340 */ 2120d979e8ebSPeter Maydell MIPS_SYS(sys_clock_adjtime, 2) 2121d979e8ebSPeter Maydell MIPS_SYS(sys_syncfs, 1) 2122048f6b4dSbellard }; 2123048f6b4dSbellard 2124048f6b4dSbellard #undef MIPS_SYS 2125048f6b4dSbellard 2126590bc601SPaul Brook static int do_store_exclusive(CPUMIPSState *env) 2127590bc601SPaul Brook { 2128590bc601SPaul Brook target_ulong addr; 2129590bc601SPaul Brook target_ulong page_addr; 2130590bc601SPaul Brook target_ulong val; 2131590bc601SPaul Brook int flags; 2132590bc601SPaul Brook int segv = 0; 2133590bc601SPaul Brook int reg; 2134590bc601SPaul Brook int d; 2135590bc601SPaul Brook 21365499b6ffSAurelien Jarno addr = env->lladdr; 2137590bc601SPaul Brook page_addr = addr & TARGET_PAGE_MASK; 2138590bc601SPaul Brook start_exclusive(); 2139590bc601SPaul Brook mmap_lock(); 2140590bc601SPaul Brook flags = page_get_flags(page_addr); 2141590bc601SPaul Brook if ((flags & PAGE_READ) == 0) { 2142590bc601SPaul Brook segv = 1; 2143590bc601SPaul Brook } else { 2144590bc601SPaul Brook reg = env->llreg & 0x1f; 2145590bc601SPaul Brook d = (env->llreg & 0x20) != 0; 2146590bc601SPaul Brook if (d) { 2147590bc601SPaul Brook segv = get_user_s64(val, addr); 2148590bc601SPaul Brook } else { 2149590bc601SPaul Brook segv = get_user_s32(val, addr); 2150590bc601SPaul Brook } 2151590bc601SPaul Brook if (!segv) { 2152590bc601SPaul Brook if (val != env->llval) { 2153590bc601SPaul Brook env->active_tc.gpr[reg] = 0; 2154590bc601SPaul Brook } else { 2155590bc601SPaul Brook if (d) { 2156590bc601SPaul Brook segv = put_user_u64(env->llnewval, addr); 2157590bc601SPaul Brook } else { 2158590bc601SPaul Brook segv = put_user_u32(env->llnewval, addr); 2159590bc601SPaul Brook } 2160590bc601SPaul Brook if (!segv) { 2161590bc601SPaul Brook env->active_tc.gpr[reg] = 1; 2162590bc601SPaul Brook } 2163590bc601SPaul Brook } 2164590bc601SPaul Brook } 2165590bc601SPaul Brook } 21665499b6ffSAurelien Jarno env->lladdr = -1; 2167590bc601SPaul Brook if (!segv) { 2168590bc601SPaul Brook env->active_tc.PC += 4; 2169590bc601SPaul Brook } 2170590bc601SPaul Brook mmap_unlock(); 2171590bc601SPaul Brook end_exclusive(); 2172590bc601SPaul Brook return segv; 2173590bc601SPaul Brook } 2174590bc601SPaul Brook 2175048f6b4dSbellard void cpu_loop(CPUMIPSState *env) 2176048f6b4dSbellard { 2177c227f099SAnthony Liguori target_siginfo_t info; 2178388bb21aSths int trapnr, ret; 2179048f6b4dSbellard unsigned int syscall_num; 2180048f6b4dSbellard 2181048f6b4dSbellard for(;;) { 2182590bc601SPaul Brook cpu_exec_start(env); 2183048f6b4dSbellard trapnr = cpu_mips_exec(env); 2184590bc601SPaul Brook cpu_exec_end(env); 2185048f6b4dSbellard switch(trapnr) { 2186048f6b4dSbellard case EXCP_SYSCALL: 2187b5dc7732Sths syscall_num = env->active_tc.gpr[2] - 4000; 2188b5dc7732Sths env->active_tc.PC += 4; 2189048f6b4dSbellard if (syscall_num >= sizeof(mips_syscall_args)) { 21907c2f6157SWesley W. Terpstra ret = -TARGET_ENOSYS; 2191048f6b4dSbellard } else { 2192388bb21aSths int nb_args; 2193992f48a0Sblueswir1 abi_ulong sp_reg; 2194992f48a0Sblueswir1 abi_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0; 2195388bb21aSths 2196048f6b4dSbellard nb_args = mips_syscall_args[syscall_num]; 2197b5dc7732Sths sp_reg = env->active_tc.gpr[29]; 2198388bb21aSths switch (nb_args) { 2199048f6b4dSbellard /* these arguments are taken from the stack */ 220094c19610SAn-Cheng Huang case 8: 220194c19610SAn-Cheng Huang if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) { 220294c19610SAn-Cheng Huang goto done_syscall; 220394c19610SAn-Cheng Huang } 220494c19610SAn-Cheng Huang case 7: 220594c19610SAn-Cheng Huang if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) { 220694c19610SAn-Cheng Huang goto done_syscall; 220794c19610SAn-Cheng Huang } 220894c19610SAn-Cheng Huang case 6: 220994c19610SAn-Cheng Huang if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) { 221094c19610SAn-Cheng Huang goto done_syscall; 221194c19610SAn-Cheng Huang } 221294c19610SAn-Cheng Huang case 5: 221394c19610SAn-Cheng Huang if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) { 221494c19610SAn-Cheng Huang goto done_syscall; 221594c19610SAn-Cheng Huang } 2216388bb21aSths default: 2217388bb21aSths break; 2218048f6b4dSbellard } 2219b5dc7732Sths ret = do_syscall(env, env->active_tc.gpr[2], 2220b5dc7732Sths env->active_tc.gpr[4], 2221b5dc7732Sths env->active_tc.gpr[5], 2222b5dc7732Sths env->active_tc.gpr[6], 2223b5dc7732Sths env->active_tc.gpr[7], 22245945cfcbSPeter Maydell arg5, arg6, arg7, arg8); 2225048f6b4dSbellard } 222694c19610SAn-Cheng Huang done_syscall: 22270b1bcb00Spbrook if (ret == -TARGET_QEMU_ESIGRETURN) { 22280b1bcb00Spbrook /* Returning from a successful sigreturn syscall. 22290b1bcb00Spbrook Avoid clobbering register state. */ 22300b1bcb00Spbrook break; 22310b1bcb00Spbrook } 2232048f6b4dSbellard if ((unsigned int)ret >= (unsigned int)(-1133)) { 2233b5dc7732Sths env->active_tc.gpr[7] = 1; /* error flag */ 2234048f6b4dSbellard ret = -ret; 2235048f6b4dSbellard } else { 2236b5dc7732Sths env->active_tc.gpr[7] = 0; /* error flag */ 2237388bb21aSths } 2238b5dc7732Sths env->active_tc.gpr[2] = ret; 2239048f6b4dSbellard break; 2240ca7c2b1bSths case EXCP_TLBL: 2241ca7c2b1bSths case EXCP_TLBS: 2242e6e5bd2dSWesley W. Terpstra case EXCP_AdEL: 2243e6e5bd2dSWesley W. Terpstra case EXCP_AdES: 2244e4474235Spbrook info.si_signo = TARGET_SIGSEGV; 2245e4474235Spbrook info.si_errno = 0; 2246e4474235Spbrook /* XXX: check env->error_code */ 2247e4474235Spbrook info.si_code = TARGET_SEGV_MAPERR; 2248e4474235Spbrook info._sifields._sigfault._addr = env->CP0_BadVAddr; 2249e4474235Spbrook queue_signal(env, info.si_signo, &info); 2250e4474235Spbrook break; 22516900e84bSbellard case EXCP_CpU: 2252048f6b4dSbellard case EXCP_RI: 2253048f6b4dSbellard info.si_signo = TARGET_SIGILL; 2254048f6b4dSbellard info.si_errno = 0; 2255048f6b4dSbellard info.si_code = 0; 2256624f7979Spbrook queue_signal(env, info.si_signo, &info); 2257048f6b4dSbellard break; 2258106ec879Sbellard case EXCP_INTERRUPT: 2259106ec879Sbellard /* just indicate that signals should be handled asap */ 2260106ec879Sbellard break; 2261d08b2a28Spbrook case EXCP_DEBUG: 2262d08b2a28Spbrook { 2263d08b2a28Spbrook int sig; 2264d08b2a28Spbrook 2265d08b2a28Spbrook sig = gdb_handlesig (env, TARGET_SIGTRAP); 2266d08b2a28Spbrook if (sig) 2267d08b2a28Spbrook { 2268d08b2a28Spbrook info.si_signo = sig; 2269d08b2a28Spbrook info.si_errno = 0; 2270d08b2a28Spbrook info.si_code = TARGET_TRAP_BRKPT; 2271624f7979Spbrook queue_signal(env, info.si_signo, &info); 2272d08b2a28Spbrook } 2273d08b2a28Spbrook } 2274d08b2a28Spbrook break; 2275590bc601SPaul Brook case EXCP_SC: 2276590bc601SPaul Brook if (do_store_exclusive(env)) { 2277590bc601SPaul Brook info.si_signo = TARGET_SIGSEGV; 2278590bc601SPaul Brook info.si_errno = 0; 2279590bc601SPaul Brook info.si_code = TARGET_SEGV_MAPERR; 2280590bc601SPaul Brook info._sifields._sigfault._addr = env->active_tc.PC; 2281590bc601SPaul Brook queue_signal(env, info.si_signo, &info); 2282590bc601SPaul Brook } 2283590bc601SPaul Brook break; 2284048f6b4dSbellard default: 2285048f6b4dSbellard // error: 2286048f6b4dSbellard fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 2287048f6b4dSbellard trapnr); 2288048f6b4dSbellard cpu_dump_state(env, stderr, fprintf, 0); 2289048f6b4dSbellard abort(); 2290048f6b4dSbellard } 2291048f6b4dSbellard process_pending_signals(env); 2292048f6b4dSbellard } 2293048f6b4dSbellard } 2294048f6b4dSbellard #endif 2295048f6b4dSbellard 2296d962783eSJia Liu #ifdef TARGET_OPENRISC 2297d962783eSJia Liu 2298d962783eSJia Liu void cpu_loop(CPUOpenRISCState *env) 2299d962783eSJia Liu { 2300d962783eSJia Liu int trapnr, gdbsig; 2301d962783eSJia Liu 2302d962783eSJia Liu for (;;) { 2303d962783eSJia Liu trapnr = cpu_exec(env); 2304d962783eSJia Liu gdbsig = 0; 2305d962783eSJia Liu 2306d962783eSJia Liu switch (trapnr) { 2307d962783eSJia Liu case EXCP_RESET: 2308d962783eSJia Liu qemu_log("\nReset request, exit, pc is %#x\n", env->pc); 2309d962783eSJia Liu exit(1); 2310d962783eSJia Liu break; 2311d962783eSJia Liu case EXCP_BUSERR: 2312d962783eSJia Liu qemu_log("\nBus error, exit, pc is %#x\n", env->pc); 2313d962783eSJia Liu gdbsig = SIGBUS; 2314d962783eSJia Liu break; 2315d962783eSJia Liu case EXCP_DPF: 2316d962783eSJia Liu case EXCP_IPF: 2317d962783eSJia Liu cpu_dump_state(env, stderr, fprintf, 0); 2318d962783eSJia Liu gdbsig = TARGET_SIGSEGV; 2319d962783eSJia Liu break; 2320d962783eSJia Liu case EXCP_TICK: 2321d962783eSJia Liu qemu_log("\nTick time interrupt pc is %#x\n", env->pc); 2322d962783eSJia Liu break; 2323d962783eSJia Liu case EXCP_ALIGN: 2324d962783eSJia Liu qemu_log("\nAlignment pc is %#x\n", env->pc); 2325d962783eSJia Liu gdbsig = SIGBUS; 2326d962783eSJia Liu break; 2327d962783eSJia Liu case EXCP_ILLEGAL: 2328d962783eSJia Liu qemu_log("\nIllegal instructionpc is %#x\n", env->pc); 2329d962783eSJia Liu gdbsig = SIGILL; 2330d962783eSJia Liu break; 2331d962783eSJia Liu case EXCP_INT: 2332d962783eSJia Liu qemu_log("\nExternal interruptpc is %#x\n", env->pc); 2333d962783eSJia Liu break; 2334d962783eSJia Liu case EXCP_DTLBMISS: 2335d962783eSJia Liu case EXCP_ITLBMISS: 2336d962783eSJia Liu qemu_log("\nTLB miss\n"); 2337d962783eSJia Liu break; 2338d962783eSJia Liu case EXCP_RANGE: 2339d962783eSJia Liu qemu_log("\nRange\n"); 2340d962783eSJia Liu gdbsig = SIGSEGV; 2341d962783eSJia Liu break; 2342d962783eSJia Liu case EXCP_SYSCALL: 2343d962783eSJia Liu env->pc += 4; /* 0xc00; */ 2344d962783eSJia Liu env->gpr[11] = do_syscall(env, 2345d962783eSJia Liu env->gpr[11], /* return value */ 2346d962783eSJia Liu env->gpr[3], /* r3 - r7 are params */ 2347d962783eSJia Liu env->gpr[4], 2348d962783eSJia Liu env->gpr[5], 2349d962783eSJia Liu env->gpr[6], 2350d962783eSJia Liu env->gpr[7], 2351d962783eSJia Liu env->gpr[8], 0, 0); 2352d962783eSJia Liu break; 2353d962783eSJia Liu case EXCP_FPE: 2354d962783eSJia Liu qemu_log("\nFloating point error\n"); 2355d962783eSJia Liu break; 2356d962783eSJia Liu case EXCP_TRAP: 2357d962783eSJia Liu qemu_log("\nTrap\n"); 2358d962783eSJia Liu gdbsig = SIGTRAP; 2359d962783eSJia Liu break; 2360d962783eSJia Liu case EXCP_NR: 2361d962783eSJia Liu qemu_log("\nNR\n"); 2362d962783eSJia Liu break; 2363d962783eSJia Liu default: 2364d962783eSJia Liu qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n", 2365d962783eSJia Liu trapnr); 2366d962783eSJia Liu cpu_dump_state(env, stderr, fprintf, 0); 2367d962783eSJia Liu gdbsig = TARGET_SIGILL; 2368d962783eSJia Liu break; 2369d962783eSJia Liu } 2370d962783eSJia Liu if (gdbsig) { 2371d962783eSJia Liu gdb_handlesig(env, gdbsig); 2372d962783eSJia Liu if (gdbsig != TARGET_SIGTRAP) { 2373d962783eSJia Liu exit(1); 2374d962783eSJia Liu } 2375d962783eSJia Liu } 2376d962783eSJia Liu 2377d962783eSJia Liu process_pending_signals(env); 2378d962783eSJia Liu } 2379d962783eSJia Liu } 2380d962783eSJia Liu 2381d962783eSJia Liu #endif /* TARGET_OPENRISC */ 2382d962783eSJia Liu 2383fdf9b3e8Sbellard #ifdef TARGET_SH4 238405390248SAndreas Färber void cpu_loop(CPUSH4State *env) 2385fdf9b3e8Sbellard { 2386fdf9b3e8Sbellard int trapnr, ret; 2387c227f099SAnthony Liguori target_siginfo_t info; 2388fdf9b3e8Sbellard 2389fdf9b3e8Sbellard while (1) { 2390fdf9b3e8Sbellard trapnr = cpu_sh4_exec (env); 2391fdf9b3e8Sbellard 2392fdf9b3e8Sbellard switch (trapnr) { 2393fdf9b3e8Sbellard case 0x160: 23940b6d3ae0Saurel32 env->pc += 2; 2395fdf9b3e8Sbellard ret = do_syscall(env, 23969c2a9ea1Spbrook env->gregs[3], 23979c2a9ea1Spbrook env->gregs[4], 23989c2a9ea1Spbrook env->gregs[5], 23999c2a9ea1Spbrook env->gregs[6], 24009c2a9ea1Spbrook env->gregs[7], 24019c2a9ea1Spbrook env->gregs[0], 24025945cfcbSPeter Maydell env->gregs[1], 24035945cfcbSPeter Maydell 0, 0); 24049c2a9ea1Spbrook env->gregs[0] = ret; 2405fdf9b3e8Sbellard break; 2406c3b5bc8aSths case EXCP_INTERRUPT: 2407c3b5bc8aSths /* just indicate that signals should be handled asap */ 2408c3b5bc8aSths break; 2409355fb23dSpbrook case EXCP_DEBUG: 2410355fb23dSpbrook { 2411355fb23dSpbrook int sig; 2412355fb23dSpbrook 2413355fb23dSpbrook sig = gdb_handlesig (env, TARGET_SIGTRAP); 2414355fb23dSpbrook if (sig) 2415355fb23dSpbrook { 2416355fb23dSpbrook info.si_signo = sig; 2417355fb23dSpbrook info.si_errno = 0; 2418355fb23dSpbrook info.si_code = TARGET_TRAP_BRKPT; 2419624f7979Spbrook queue_signal(env, info.si_signo, &info); 2420355fb23dSpbrook } 2421355fb23dSpbrook } 2422355fb23dSpbrook break; 2423c3b5bc8aSths case 0xa0: 2424c3b5bc8aSths case 0xc0: 2425c3b5bc8aSths info.si_signo = SIGSEGV; 2426c3b5bc8aSths info.si_errno = 0; 2427c3b5bc8aSths info.si_code = TARGET_SEGV_MAPERR; 2428c3b5bc8aSths info._sifields._sigfault._addr = env->tea; 2429624f7979Spbrook queue_signal(env, info.si_signo, &info); 2430c3b5bc8aSths break; 2431c3b5bc8aSths 2432fdf9b3e8Sbellard default: 2433fdf9b3e8Sbellard printf ("Unhandled trap: 0x%x\n", trapnr); 2434fdf9b3e8Sbellard cpu_dump_state(env, stderr, fprintf, 0); 2435fdf9b3e8Sbellard exit (1); 2436fdf9b3e8Sbellard } 2437fdf9b3e8Sbellard process_pending_signals (env); 2438fdf9b3e8Sbellard } 2439fdf9b3e8Sbellard } 2440fdf9b3e8Sbellard #endif 2441fdf9b3e8Sbellard 244248733d19Sths #ifdef TARGET_CRIS 244305390248SAndreas Färber void cpu_loop(CPUCRISState *env) 244448733d19Sths { 244548733d19Sths int trapnr, ret; 2446c227f099SAnthony Liguori target_siginfo_t info; 244748733d19Sths 244848733d19Sths while (1) { 244948733d19Sths trapnr = cpu_cris_exec (env); 245048733d19Sths switch (trapnr) { 245148733d19Sths case 0xaa: 245248733d19Sths { 245348733d19Sths info.si_signo = SIGSEGV; 245448733d19Sths info.si_errno = 0; 245548733d19Sths /* XXX: check env->error_code */ 245648733d19Sths info.si_code = TARGET_SEGV_MAPERR; 2457e00c1e71Sedgar_igl info._sifields._sigfault._addr = env->pregs[PR_EDA]; 2458624f7979Spbrook queue_signal(env, info.si_signo, &info); 245948733d19Sths } 246048733d19Sths break; 2461b6d3abdaSedgar_igl case EXCP_INTERRUPT: 2462b6d3abdaSedgar_igl /* just indicate that signals should be handled asap */ 2463b6d3abdaSedgar_igl break; 246448733d19Sths case EXCP_BREAK: 246548733d19Sths ret = do_syscall(env, 246648733d19Sths env->regs[9], 246748733d19Sths env->regs[10], 246848733d19Sths env->regs[11], 246948733d19Sths env->regs[12], 247048733d19Sths env->regs[13], 247148733d19Sths env->pregs[7], 24725945cfcbSPeter Maydell env->pregs[11], 24735945cfcbSPeter Maydell 0, 0); 247448733d19Sths env->regs[10] = ret; 247548733d19Sths break; 247648733d19Sths case EXCP_DEBUG: 247748733d19Sths { 247848733d19Sths int sig; 247948733d19Sths 248048733d19Sths sig = gdb_handlesig (env, TARGET_SIGTRAP); 248148733d19Sths if (sig) 248248733d19Sths { 248348733d19Sths info.si_signo = sig; 248448733d19Sths info.si_errno = 0; 248548733d19Sths info.si_code = TARGET_TRAP_BRKPT; 2486624f7979Spbrook queue_signal(env, info.si_signo, &info); 248748733d19Sths } 248848733d19Sths } 248948733d19Sths break; 249048733d19Sths default: 249148733d19Sths printf ("Unhandled trap: 0x%x\n", trapnr); 249248733d19Sths cpu_dump_state(env, stderr, fprintf, 0); 249348733d19Sths exit (1); 249448733d19Sths } 249548733d19Sths process_pending_signals (env); 249648733d19Sths } 249748733d19Sths } 249848733d19Sths #endif 249948733d19Sths 2500b779e29eSEdgar E. Iglesias #ifdef TARGET_MICROBLAZE 250105390248SAndreas Färber void cpu_loop(CPUMBState *env) 2502b779e29eSEdgar E. Iglesias { 2503b779e29eSEdgar E. Iglesias int trapnr, ret; 2504c227f099SAnthony Liguori target_siginfo_t info; 2505b779e29eSEdgar E. Iglesias 2506b779e29eSEdgar E. Iglesias while (1) { 2507b779e29eSEdgar E. Iglesias trapnr = cpu_mb_exec (env); 2508b779e29eSEdgar E. Iglesias switch (trapnr) { 2509b779e29eSEdgar E. Iglesias case 0xaa: 2510b779e29eSEdgar E. Iglesias { 2511b779e29eSEdgar E. Iglesias info.si_signo = SIGSEGV; 2512b779e29eSEdgar E. Iglesias info.si_errno = 0; 2513b779e29eSEdgar E. Iglesias /* XXX: check env->error_code */ 2514b779e29eSEdgar E. Iglesias info.si_code = TARGET_SEGV_MAPERR; 2515b779e29eSEdgar E. Iglesias info._sifields._sigfault._addr = 0; 2516b779e29eSEdgar E. Iglesias queue_signal(env, info.si_signo, &info); 2517b779e29eSEdgar E. Iglesias } 2518b779e29eSEdgar E. Iglesias break; 2519b779e29eSEdgar E. Iglesias case EXCP_INTERRUPT: 2520b779e29eSEdgar E. Iglesias /* just indicate that signals should be handled asap */ 2521b779e29eSEdgar E. Iglesias break; 2522b779e29eSEdgar E. Iglesias case EXCP_BREAK: 2523b779e29eSEdgar E. Iglesias /* Return address is 4 bytes after the call. */ 2524b779e29eSEdgar E. Iglesias env->regs[14] += 4; 2525b779e29eSEdgar E. Iglesias ret = do_syscall(env, 2526b779e29eSEdgar E. Iglesias env->regs[12], 2527b779e29eSEdgar E. Iglesias env->regs[5], 2528b779e29eSEdgar E. Iglesias env->regs[6], 2529b779e29eSEdgar E. Iglesias env->regs[7], 2530b779e29eSEdgar E. Iglesias env->regs[8], 2531b779e29eSEdgar E. Iglesias env->regs[9], 25325945cfcbSPeter Maydell env->regs[10], 25335945cfcbSPeter Maydell 0, 0); 2534b779e29eSEdgar E. Iglesias env->regs[3] = ret; 2535b779e29eSEdgar E. Iglesias env->sregs[SR_PC] = env->regs[14]; 2536b779e29eSEdgar E. Iglesias break; 2537b76da7e3SEdgar E. Iglesias case EXCP_HW_EXCP: 2538b76da7e3SEdgar E. Iglesias env->regs[17] = env->sregs[SR_PC] + 4; 2539b76da7e3SEdgar E. Iglesias if (env->iflags & D_FLAG) { 2540b76da7e3SEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 12; 2541b76da7e3SEdgar E. Iglesias env->sregs[SR_PC] -= 4; 2542b76da7e3SEdgar E. Iglesias /* FIXME: if branch was immed, replay the imm as well. */ 2543b76da7e3SEdgar E. Iglesias } 2544b76da7e3SEdgar E. Iglesias 2545b76da7e3SEdgar E. Iglesias env->iflags &= ~(IMM_FLAG | D_FLAG); 2546b76da7e3SEdgar E. Iglesias 2547b76da7e3SEdgar E. Iglesias switch (env->sregs[SR_ESR] & 31) { 254822a78d64SEdgar E. Iglesias case ESR_EC_DIVZERO: 254922a78d64SEdgar E. Iglesias info.si_signo = SIGFPE; 255022a78d64SEdgar E. Iglesias info.si_errno = 0; 255122a78d64SEdgar E. Iglesias info.si_code = TARGET_FPE_FLTDIV; 255222a78d64SEdgar E. Iglesias info._sifields._sigfault._addr = 0; 255322a78d64SEdgar E. Iglesias queue_signal(env, info.si_signo, &info); 255422a78d64SEdgar E. Iglesias break; 2555b76da7e3SEdgar E. Iglesias case ESR_EC_FPU: 2556b76da7e3SEdgar E. Iglesias info.si_signo = SIGFPE; 2557b76da7e3SEdgar E. Iglesias info.si_errno = 0; 2558b76da7e3SEdgar E. Iglesias if (env->sregs[SR_FSR] & FSR_IO) { 2559b76da7e3SEdgar E. Iglesias info.si_code = TARGET_FPE_FLTINV; 2560b76da7e3SEdgar E. Iglesias } 2561b76da7e3SEdgar E. Iglesias if (env->sregs[SR_FSR] & FSR_DZ) { 2562b76da7e3SEdgar E. Iglesias info.si_code = TARGET_FPE_FLTDIV; 2563b76da7e3SEdgar E. Iglesias } 2564b76da7e3SEdgar E. Iglesias info._sifields._sigfault._addr = 0; 2565b76da7e3SEdgar E. Iglesias queue_signal(env, info.si_signo, &info); 2566b76da7e3SEdgar E. Iglesias break; 2567b76da7e3SEdgar E. Iglesias default: 2568b76da7e3SEdgar E. Iglesias printf ("Unhandled hw-exception: 0x%x\n", 25692e42d52dSEdgar E. Iglesias env->sregs[SR_ESR] & ESR_EC_MASK); 2570b76da7e3SEdgar E. Iglesias cpu_dump_state(env, stderr, fprintf, 0); 2571b76da7e3SEdgar E. Iglesias exit (1); 2572b76da7e3SEdgar E. Iglesias break; 2573b76da7e3SEdgar E. Iglesias } 2574b76da7e3SEdgar E. Iglesias break; 2575b779e29eSEdgar E. Iglesias case EXCP_DEBUG: 2576b779e29eSEdgar E. Iglesias { 2577b779e29eSEdgar E. Iglesias int sig; 2578b779e29eSEdgar E. Iglesias 2579b779e29eSEdgar E. Iglesias sig = gdb_handlesig (env, TARGET_SIGTRAP); 2580b779e29eSEdgar E. Iglesias if (sig) 2581b779e29eSEdgar E. Iglesias { 2582b779e29eSEdgar E. Iglesias info.si_signo = sig; 2583b779e29eSEdgar E. Iglesias info.si_errno = 0; 2584b779e29eSEdgar E. Iglesias info.si_code = TARGET_TRAP_BRKPT; 2585b779e29eSEdgar E. Iglesias queue_signal(env, info.si_signo, &info); 2586b779e29eSEdgar E. Iglesias } 2587b779e29eSEdgar E. Iglesias } 2588b779e29eSEdgar E. Iglesias break; 2589b779e29eSEdgar E. Iglesias default: 2590b779e29eSEdgar E. Iglesias printf ("Unhandled trap: 0x%x\n", trapnr); 2591b779e29eSEdgar E. Iglesias cpu_dump_state(env, stderr, fprintf, 0); 2592b779e29eSEdgar E. Iglesias exit (1); 2593b779e29eSEdgar E. Iglesias } 2594b779e29eSEdgar E. Iglesias process_pending_signals (env); 2595b779e29eSEdgar E. Iglesias } 2596b779e29eSEdgar E. Iglesias } 2597b779e29eSEdgar E. Iglesias #endif 2598b779e29eSEdgar E. Iglesias 2599e6e5906bSpbrook #ifdef TARGET_M68K 2600e6e5906bSpbrook 2601e6e5906bSpbrook void cpu_loop(CPUM68KState *env) 2602e6e5906bSpbrook { 2603e6e5906bSpbrook int trapnr; 2604e6e5906bSpbrook unsigned int n; 2605c227f099SAnthony Liguori target_siginfo_t info; 2606e6e5906bSpbrook TaskState *ts = env->opaque; 2607e6e5906bSpbrook 2608e6e5906bSpbrook for(;;) { 2609e6e5906bSpbrook trapnr = cpu_m68k_exec(env); 2610e6e5906bSpbrook switch(trapnr) { 2611e6e5906bSpbrook case EXCP_ILLEGAL: 2612e6e5906bSpbrook { 2613e6e5906bSpbrook if (ts->sim_syscalls) { 2614e6e5906bSpbrook uint16_t nr; 2615e6e5906bSpbrook nr = lduw(env->pc + 2); 2616e6e5906bSpbrook env->pc += 4; 2617e6e5906bSpbrook do_m68k_simcall(env, nr); 2618e6e5906bSpbrook } else { 2619e6e5906bSpbrook goto do_sigill; 2620e6e5906bSpbrook } 2621e6e5906bSpbrook } 2622e6e5906bSpbrook break; 2623a87295e8Spbrook case EXCP_HALT_INSN: 2624e6e5906bSpbrook /* Semihosing syscall. */ 2625a87295e8Spbrook env->pc += 4; 2626e6e5906bSpbrook do_m68k_semihosting(env, env->dregs[0]); 2627e6e5906bSpbrook break; 2628e6e5906bSpbrook case EXCP_LINEA: 2629e6e5906bSpbrook case EXCP_LINEF: 2630e6e5906bSpbrook case EXCP_UNSUPPORTED: 2631e6e5906bSpbrook do_sigill: 2632e6e5906bSpbrook info.si_signo = SIGILL; 2633e6e5906bSpbrook info.si_errno = 0; 2634e6e5906bSpbrook info.si_code = TARGET_ILL_ILLOPN; 2635e6e5906bSpbrook info._sifields._sigfault._addr = env->pc; 2636624f7979Spbrook queue_signal(env, info.si_signo, &info); 2637e6e5906bSpbrook break; 2638e6e5906bSpbrook case EXCP_TRAP0: 2639e6e5906bSpbrook { 2640e6e5906bSpbrook ts->sim_syscalls = 0; 2641e6e5906bSpbrook n = env->dregs[0]; 2642e6e5906bSpbrook env->pc += 2; 2643e6e5906bSpbrook env->dregs[0] = do_syscall(env, 2644e6e5906bSpbrook n, 2645e6e5906bSpbrook env->dregs[1], 2646e6e5906bSpbrook env->dregs[2], 2647e6e5906bSpbrook env->dregs[3], 2648e6e5906bSpbrook env->dregs[4], 2649e6e5906bSpbrook env->dregs[5], 26505945cfcbSPeter Maydell env->aregs[0], 26515945cfcbSPeter Maydell 0, 0); 2652e6e5906bSpbrook } 2653e6e5906bSpbrook break; 2654e6e5906bSpbrook case EXCP_INTERRUPT: 2655e6e5906bSpbrook /* just indicate that signals should be handled asap */ 2656e6e5906bSpbrook break; 2657e6e5906bSpbrook case EXCP_ACCESS: 2658e6e5906bSpbrook { 2659e6e5906bSpbrook info.si_signo = SIGSEGV; 2660e6e5906bSpbrook info.si_errno = 0; 2661e6e5906bSpbrook /* XXX: check env->error_code */ 2662e6e5906bSpbrook info.si_code = TARGET_SEGV_MAPERR; 2663e6e5906bSpbrook info._sifields._sigfault._addr = env->mmu.ar; 2664624f7979Spbrook queue_signal(env, info.si_signo, &info); 2665e6e5906bSpbrook } 2666e6e5906bSpbrook break; 2667e6e5906bSpbrook case EXCP_DEBUG: 2668e6e5906bSpbrook { 2669e6e5906bSpbrook int sig; 2670e6e5906bSpbrook 2671e6e5906bSpbrook sig = gdb_handlesig (env, TARGET_SIGTRAP); 2672e6e5906bSpbrook if (sig) 2673e6e5906bSpbrook { 2674e6e5906bSpbrook info.si_signo = sig; 2675e6e5906bSpbrook info.si_errno = 0; 2676e6e5906bSpbrook info.si_code = TARGET_TRAP_BRKPT; 2677624f7979Spbrook queue_signal(env, info.si_signo, &info); 2678e6e5906bSpbrook } 2679e6e5906bSpbrook } 2680e6e5906bSpbrook break; 2681e6e5906bSpbrook default: 2682e6e5906bSpbrook fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 2683e6e5906bSpbrook trapnr); 2684e6e5906bSpbrook cpu_dump_state(env, stderr, fprintf, 0); 2685e6e5906bSpbrook abort(); 2686e6e5906bSpbrook } 2687e6e5906bSpbrook process_pending_signals(env); 2688e6e5906bSpbrook } 2689e6e5906bSpbrook } 2690e6e5906bSpbrook #endif /* TARGET_M68K */ 2691e6e5906bSpbrook 26927a3148a9Sj_mayer #ifdef TARGET_ALPHA 26936910b8f6SRichard Henderson static void do_store_exclusive(CPUAlphaState *env, int reg, int quad) 26946910b8f6SRichard Henderson { 26956910b8f6SRichard Henderson target_ulong addr, val, tmp; 26966910b8f6SRichard Henderson target_siginfo_t info; 26976910b8f6SRichard Henderson int ret = 0; 26986910b8f6SRichard Henderson 26996910b8f6SRichard Henderson addr = env->lock_addr; 27006910b8f6SRichard Henderson tmp = env->lock_st_addr; 27016910b8f6SRichard Henderson env->lock_addr = -1; 27026910b8f6SRichard Henderson env->lock_st_addr = 0; 27036910b8f6SRichard Henderson 27046910b8f6SRichard Henderson start_exclusive(); 27056910b8f6SRichard Henderson mmap_lock(); 27066910b8f6SRichard Henderson 27076910b8f6SRichard Henderson if (addr == tmp) { 27086910b8f6SRichard Henderson if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) { 27096910b8f6SRichard Henderson goto do_sigsegv; 27106910b8f6SRichard Henderson } 27116910b8f6SRichard Henderson 27126910b8f6SRichard Henderson if (val == env->lock_value) { 27136910b8f6SRichard Henderson tmp = env->ir[reg]; 27146910b8f6SRichard Henderson if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) { 27156910b8f6SRichard Henderson goto do_sigsegv; 27166910b8f6SRichard Henderson } 27176910b8f6SRichard Henderson ret = 1; 27186910b8f6SRichard Henderson } 27196910b8f6SRichard Henderson } 27206910b8f6SRichard Henderson env->ir[reg] = ret; 27216910b8f6SRichard Henderson env->pc += 4; 27226910b8f6SRichard Henderson 27236910b8f6SRichard Henderson mmap_unlock(); 27246910b8f6SRichard Henderson end_exclusive(); 27256910b8f6SRichard Henderson return; 27266910b8f6SRichard Henderson 27276910b8f6SRichard Henderson do_sigsegv: 27286910b8f6SRichard Henderson mmap_unlock(); 27296910b8f6SRichard Henderson end_exclusive(); 27306910b8f6SRichard Henderson 27316910b8f6SRichard Henderson info.si_signo = TARGET_SIGSEGV; 27326910b8f6SRichard Henderson info.si_errno = 0; 27336910b8f6SRichard Henderson info.si_code = TARGET_SEGV_MAPERR; 27346910b8f6SRichard Henderson info._sifields._sigfault._addr = addr; 27356910b8f6SRichard Henderson queue_signal(env, TARGET_SIGSEGV, &info); 27366910b8f6SRichard Henderson } 27376910b8f6SRichard Henderson 273805390248SAndreas Färber void cpu_loop(CPUAlphaState *env) 27397a3148a9Sj_mayer { 2740e96efcfcSj_mayer int trapnr; 2741c227f099SAnthony Liguori target_siginfo_t info; 27426049f4f8SRichard Henderson abi_long sysret; 27437a3148a9Sj_mayer 27447a3148a9Sj_mayer while (1) { 27457a3148a9Sj_mayer trapnr = cpu_alpha_exec (env); 27467a3148a9Sj_mayer 2747ac316ca4SRichard Henderson /* All of the traps imply a transition through PALcode, which 2748ac316ca4SRichard Henderson implies an REI instruction has been executed. Which means 2749ac316ca4SRichard Henderson that the intr_flag should be cleared. */ 2750ac316ca4SRichard Henderson env->intr_flag = 0; 2751ac316ca4SRichard Henderson 27527a3148a9Sj_mayer switch (trapnr) { 27537a3148a9Sj_mayer case EXCP_RESET: 27547a3148a9Sj_mayer fprintf(stderr, "Reset requested. Exit\n"); 27557a3148a9Sj_mayer exit(1); 27567a3148a9Sj_mayer break; 27577a3148a9Sj_mayer case EXCP_MCHK: 27587a3148a9Sj_mayer fprintf(stderr, "Machine check exception. Exit\n"); 27597a3148a9Sj_mayer exit(1); 27607a3148a9Sj_mayer break; 276107b6c13bSRichard Henderson case EXCP_SMP_INTERRUPT: 276207b6c13bSRichard Henderson case EXCP_CLK_INTERRUPT: 276307b6c13bSRichard Henderson case EXCP_DEV_INTERRUPT: 27647a3148a9Sj_mayer fprintf(stderr, "External interrupt. Exit\n"); 27657a3148a9Sj_mayer exit(1); 27667a3148a9Sj_mayer break; 276707b6c13bSRichard Henderson case EXCP_MMFAULT: 27686910b8f6SRichard Henderson env->lock_addr = -1; 27696049f4f8SRichard Henderson info.si_signo = TARGET_SIGSEGV; 27706049f4f8SRichard Henderson info.si_errno = 0; 2771129d8aa5SRichard Henderson info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID 27720be1d07cSRichard Henderson ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR); 2773129d8aa5SRichard Henderson info._sifields._sigfault._addr = env->trap_arg0; 27746049f4f8SRichard Henderson queue_signal(env, info.si_signo, &info); 27757a3148a9Sj_mayer break; 27767a3148a9Sj_mayer case EXCP_UNALIGN: 27776910b8f6SRichard Henderson env->lock_addr = -1; 27786049f4f8SRichard Henderson info.si_signo = TARGET_SIGBUS; 27796049f4f8SRichard Henderson info.si_errno = 0; 27806049f4f8SRichard Henderson info.si_code = TARGET_BUS_ADRALN; 2781129d8aa5SRichard Henderson info._sifields._sigfault._addr = env->trap_arg0; 27826049f4f8SRichard Henderson queue_signal(env, info.si_signo, &info); 27837a3148a9Sj_mayer break; 27847a3148a9Sj_mayer case EXCP_OPCDEC: 27856049f4f8SRichard Henderson do_sigill: 27866910b8f6SRichard Henderson env->lock_addr = -1; 27876049f4f8SRichard Henderson info.si_signo = TARGET_SIGILL; 27886049f4f8SRichard Henderson info.si_errno = 0; 27896049f4f8SRichard Henderson info.si_code = TARGET_ILL_ILLOPC; 27906049f4f8SRichard Henderson info._sifields._sigfault._addr = env->pc; 27916049f4f8SRichard Henderson queue_signal(env, info.si_signo, &info); 27927a3148a9Sj_mayer break; 279307b6c13bSRichard Henderson case EXCP_ARITH: 279407b6c13bSRichard Henderson env->lock_addr = -1; 279507b6c13bSRichard Henderson info.si_signo = TARGET_SIGFPE; 279607b6c13bSRichard Henderson info.si_errno = 0; 279707b6c13bSRichard Henderson info.si_code = TARGET_FPE_FLTINV; 279807b6c13bSRichard Henderson info._sifields._sigfault._addr = env->pc; 279907b6c13bSRichard Henderson queue_signal(env, info.si_signo, &info); 280007b6c13bSRichard Henderson break; 28017a3148a9Sj_mayer case EXCP_FEN: 28026049f4f8SRichard Henderson /* No-op. Linux simply re-enables the FPU. */ 28037a3148a9Sj_mayer break; 280407b6c13bSRichard Henderson case EXCP_CALL_PAL: 28056910b8f6SRichard Henderson env->lock_addr = -1; 280607b6c13bSRichard Henderson switch (env->error_code) { 28076049f4f8SRichard Henderson case 0x80: 28086049f4f8SRichard Henderson /* BPT */ 28096049f4f8SRichard Henderson info.si_signo = TARGET_SIGTRAP; 28106049f4f8SRichard Henderson info.si_errno = 0; 28116049f4f8SRichard Henderson info.si_code = TARGET_TRAP_BRKPT; 28126049f4f8SRichard Henderson info._sifields._sigfault._addr = env->pc; 28136049f4f8SRichard Henderson queue_signal(env, info.si_signo, &info); 28146049f4f8SRichard Henderson break; 28156049f4f8SRichard Henderson case 0x81: 28166049f4f8SRichard Henderson /* BUGCHK */ 28176049f4f8SRichard Henderson info.si_signo = TARGET_SIGTRAP; 28186049f4f8SRichard Henderson info.si_errno = 0; 28196049f4f8SRichard Henderson info.si_code = 0; 28206049f4f8SRichard Henderson info._sifields._sigfault._addr = env->pc; 28216049f4f8SRichard Henderson queue_signal(env, info.si_signo, &info); 28226049f4f8SRichard Henderson break; 28236049f4f8SRichard Henderson case 0x83: 28246049f4f8SRichard Henderson /* CALLSYS */ 28256049f4f8SRichard Henderson trapnr = env->ir[IR_V0]; 28266049f4f8SRichard Henderson sysret = do_syscall(env, trapnr, 28276049f4f8SRichard Henderson env->ir[IR_A0], env->ir[IR_A1], 28286049f4f8SRichard Henderson env->ir[IR_A2], env->ir[IR_A3], 28295945cfcbSPeter Maydell env->ir[IR_A4], env->ir[IR_A5], 28305945cfcbSPeter Maydell 0, 0); 2831a5b3b13bSRichard Henderson if (trapnr == TARGET_NR_sigreturn 2832a5b3b13bSRichard Henderson || trapnr == TARGET_NR_rt_sigreturn) { 2833a5b3b13bSRichard Henderson break; 2834a5b3b13bSRichard Henderson } 2835a5b3b13bSRichard Henderson /* Syscall writes 0 to V0 to bypass error check, similar 28360e141977SRichard Henderson to how this is handled internal to Linux kernel. 28370e141977SRichard Henderson (Ab)use trapnr temporarily as boolean indicating error. */ 28380e141977SRichard Henderson trapnr = (env->ir[IR_V0] != 0 && sysret < 0); 28390e141977SRichard Henderson env->ir[IR_V0] = (trapnr ? -sysret : sysret); 28400e141977SRichard Henderson env->ir[IR_A3] = trapnr; 28416049f4f8SRichard Henderson break; 28426049f4f8SRichard Henderson case 0x86: 28436049f4f8SRichard Henderson /* IMB */ 28446049f4f8SRichard Henderson /* ??? We can probably elide the code using page_unprotect 28456049f4f8SRichard Henderson that is checking for self-modifying code. Instead we 28466049f4f8SRichard Henderson could simply call tb_flush here. Until we work out the 28476049f4f8SRichard Henderson changes required to turn off the extra write protection, 28486049f4f8SRichard Henderson this can be a no-op. */ 28496049f4f8SRichard Henderson break; 28506049f4f8SRichard Henderson case 0x9E: 28516049f4f8SRichard Henderson /* RDUNIQUE */ 28526049f4f8SRichard Henderson /* Handled in the translator for usermode. */ 28536049f4f8SRichard Henderson abort(); 28546049f4f8SRichard Henderson case 0x9F: 28556049f4f8SRichard Henderson /* WRUNIQUE */ 28566049f4f8SRichard Henderson /* Handled in the translator for usermode. */ 28576049f4f8SRichard Henderson abort(); 28586049f4f8SRichard Henderson case 0xAA: 28596049f4f8SRichard Henderson /* GENTRAP */ 28606049f4f8SRichard Henderson info.si_signo = TARGET_SIGFPE; 28616049f4f8SRichard Henderson switch (env->ir[IR_A0]) { 28626049f4f8SRichard Henderson case TARGET_GEN_INTOVF: 28636049f4f8SRichard Henderson info.si_code = TARGET_FPE_INTOVF; 28646049f4f8SRichard Henderson break; 28656049f4f8SRichard Henderson case TARGET_GEN_INTDIV: 28666049f4f8SRichard Henderson info.si_code = TARGET_FPE_INTDIV; 28676049f4f8SRichard Henderson break; 28686049f4f8SRichard Henderson case TARGET_GEN_FLTOVF: 28696049f4f8SRichard Henderson info.si_code = TARGET_FPE_FLTOVF; 28706049f4f8SRichard Henderson break; 28716049f4f8SRichard Henderson case TARGET_GEN_FLTUND: 28726049f4f8SRichard Henderson info.si_code = TARGET_FPE_FLTUND; 28736049f4f8SRichard Henderson break; 28746049f4f8SRichard Henderson case TARGET_GEN_FLTINV: 28756049f4f8SRichard Henderson info.si_code = TARGET_FPE_FLTINV; 28766049f4f8SRichard Henderson break; 28776049f4f8SRichard Henderson case TARGET_GEN_FLTINE: 28786049f4f8SRichard Henderson info.si_code = TARGET_FPE_FLTRES; 28796049f4f8SRichard Henderson break; 28806049f4f8SRichard Henderson case TARGET_GEN_ROPRAND: 28816049f4f8SRichard Henderson info.si_code = 0; 28826049f4f8SRichard Henderson break; 28836049f4f8SRichard Henderson default: 28846049f4f8SRichard Henderson info.si_signo = TARGET_SIGTRAP; 28856049f4f8SRichard Henderson info.si_code = 0; 28866049f4f8SRichard Henderson break; 28876049f4f8SRichard Henderson } 28886049f4f8SRichard Henderson info.si_errno = 0; 28896049f4f8SRichard Henderson info._sifields._sigfault._addr = env->pc; 28906049f4f8SRichard Henderson queue_signal(env, info.si_signo, &info); 28916049f4f8SRichard Henderson break; 28926049f4f8SRichard Henderson default: 28936049f4f8SRichard Henderson goto do_sigill; 28946049f4f8SRichard Henderson } 28957a3148a9Sj_mayer break; 28967a3148a9Sj_mayer case EXCP_DEBUG: 28976049f4f8SRichard Henderson info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP); 28986049f4f8SRichard Henderson if (info.si_signo) { 28996910b8f6SRichard Henderson env->lock_addr = -1; 29007a3148a9Sj_mayer info.si_errno = 0; 29017a3148a9Sj_mayer info.si_code = TARGET_TRAP_BRKPT; 2902624f7979Spbrook queue_signal(env, info.si_signo, &info); 29037a3148a9Sj_mayer } 29047a3148a9Sj_mayer break; 29056910b8f6SRichard Henderson case EXCP_STL_C: 29066910b8f6SRichard Henderson case EXCP_STQ_C: 29076910b8f6SRichard Henderson do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C); 29086910b8f6SRichard Henderson break; 2909d0f20495SRichard Henderson case EXCP_INTERRUPT: 2910d0f20495SRichard Henderson /* Just indicate that signals should be handled asap. */ 2911d0f20495SRichard Henderson break; 29127a3148a9Sj_mayer default: 29137a3148a9Sj_mayer printf ("Unhandled trap: 0x%x\n", trapnr); 29147a3148a9Sj_mayer cpu_dump_state(env, stderr, fprintf, 0); 29157a3148a9Sj_mayer exit (1); 29167a3148a9Sj_mayer } 29177a3148a9Sj_mayer process_pending_signals (env); 29187a3148a9Sj_mayer } 29197a3148a9Sj_mayer } 29207a3148a9Sj_mayer #endif /* TARGET_ALPHA */ 29217a3148a9Sj_mayer 2922a4c075f1SUlrich Hecht #ifdef TARGET_S390X 2923a4c075f1SUlrich Hecht void cpu_loop(CPUS390XState *env) 2924a4c075f1SUlrich Hecht { 2925a4c075f1SUlrich Hecht int trapnr; 2926a4c075f1SUlrich Hecht target_siginfo_t info; 2927a4c075f1SUlrich Hecht 2928a4c075f1SUlrich Hecht while (1) { 2929a4c075f1SUlrich Hecht trapnr = cpu_s390x_exec (env); 2930a4c075f1SUlrich Hecht 2931a4c075f1SUlrich Hecht switch (trapnr) { 2932a4c075f1SUlrich Hecht case EXCP_INTERRUPT: 2933a4c075f1SUlrich Hecht /* just indicate that signals should be handled asap */ 2934a4c075f1SUlrich Hecht break; 2935a4c075f1SUlrich Hecht case EXCP_DEBUG: 2936a4c075f1SUlrich Hecht { 2937a4c075f1SUlrich Hecht int sig; 2938a4c075f1SUlrich Hecht 2939a4c075f1SUlrich Hecht sig = gdb_handlesig (env, TARGET_SIGTRAP); 2940a4c075f1SUlrich Hecht if (sig) { 2941a4c075f1SUlrich Hecht info.si_signo = sig; 2942a4c075f1SUlrich Hecht info.si_errno = 0; 2943a4c075f1SUlrich Hecht info.si_code = TARGET_TRAP_BRKPT; 2944a4c075f1SUlrich Hecht queue_signal(env, info.si_signo, &info); 2945a4c075f1SUlrich Hecht } 2946a4c075f1SUlrich Hecht } 2947a4c075f1SUlrich Hecht break; 2948a4c075f1SUlrich Hecht case EXCP_SVC: 2949a4c075f1SUlrich Hecht { 2950a4c075f1SUlrich Hecht int n = env->int_svc_code; 2951a4c075f1SUlrich Hecht if (!n) { 2952a4c075f1SUlrich Hecht /* syscalls > 255 */ 2953a4c075f1SUlrich Hecht n = env->regs[1]; 2954a4c075f1SUlrich Hecht } 2955a4c075f1SUlrich Hecht env->psw.addr += env->int_svc_ilc; 2956a4c075f1SUlrich Hecht env->regs[2] = do_syscall(env, n, 2957a4c075f1SUlrich Hecht env->regs[2], 2958a4c075f1SUlrich Hecht env->regs[3], 2959a4c075f1SUlrich Hecht env->regs[4], 2960a4c075f1SUlrich Hecht env->regs[5], 2961a4c075f1SUlrich Hecht env->regs[6], 29625945cfcbSPeter Maydell env->regs[7], 29635945cfcbSPeter Maydell 0, 0); 2964a4c075f1SUlrich Hecht } 2965a4c075f1SUlrich Hecht break; 2966a4c075f1SUlrich Hecht case EXCP_ADDR: 2967a4c075f1SUlrich Hecht { 2968a4c075f1SUlrich Hecht info.si_signo = SIGSEGV; 2969a4c075f1SUlrich Hecht info.si_errno = 0; 2970a4c075f1SUlrich Hecht /* XXX: check env->error_code */ 2971a4c075f1SUlrich Hecht info.si_code = TARGET_SEGV_MAPERR; 2972a4c075f1SUlrich Hecht info._sifields._sigfault._addr = env->__excp_addr; 2973a4c075f1SUlrich Hecht queue_signal(env, info.si_signo, &info); 2974a4c075f1SUlrich Hecht } 2975a4c075f1SUlrich Hecht break; 2976a4c075f1SUlrich Hecht case EXCP_SPEC: 2977a4c075f1SUlrich Hecht { 2978a4c075f1SUlrich Hecht fprintf(stderr,"specification exception insn 0x%08x%04x\n", ldl(env->psw.addr), lduw(env->psw.addr + 4)); 2979a4c075f1SUlrich Hecht info.si_signo = SIGILL; 2980a4c075f1SUlrich Hecht info.si_errno = 0; 2981a4c075f1SUlrich Hecht info.si_code = TARGET_ILL_ILLOPC; 2982a4c075f1SUlrich Hecht info._sifields._sigfault._addr = env->__excp_addr; 2983a4c075f1SUlrich Hecht queue_signal(env, info.si_signo, &info); 2984a4c075f1SUlrich Hecht } 2985a4c075f1SUlrich Hecht break; 2986a4c075f1SUlrich Hecht default: 2987a4c075f1SUlrich Hecht printf ("Unhandled trap: 0x%x\n", trapnr); 2988a4c075f1SUlrich Hecht cpu_dump_state(env, stderr, fprintf, 0); 2989a4c075f1SUlrich Hecht exit (1); 2990a4c075f1SUlrich Hecht } 2991a4c075f1SUlrich Hecht process_pending_signals (env); 2992a4c075f1SUlrich Hecht } 2993a4c075f1SUlrich Hecht } 2994a4c075f1SUlrich Hecht 2995a4c075f1SUlrich Hecht #endif /* TARGET_S390X */ 2996a4c075f1SUlrich Hecht 29979349b4f9SAndreas Färber THREAD CPUArchState *thread_env; 299859faf6d6Sbellard 2999edf8e2afSMika Westerberg void task_settid(TaskState *ts) 3000edf8e2afSMika Westerberg { 3001edf8e2afSMika Westerberg if (ts->ts_tid == 0) { 30022f7bb878SJuan Quintela #ifdef CONFIG_USE_NPTL 3003edf8e2afSMika Westerberg ts->ts_tid = (pid_t)syscall(SYS_gettid); 3004edf8e2afSMika Westerberg #else 3005edf8e2afSMika Westerberg /* when no threads are used, tid becomes pid */ 3006edf8e2afSMika Westerberg ts->ts_tid = getpid(); 3007edf8e2afSMika Westerberg #endif 3008edf8e2afSMika Westerberg } 3009edf8e2afSMika Westerberg } 3010edf8e2afSMika Westerberg 3011edf8e2afSMika Westerberg void stop_all_tasks(void) 3012edf8e2afSMika Westerberg { 3013edf8e2afSMika Westerberg /* 3014edf8e2afSMika Westerberg * We trust that when using NPTL, start_exclusive() 3015edf8e2afSMika Westerberg * handles thread stopping correctly. 3016edf8e2afSMika Westerberg */ 3017edf8e2afSMika Westerberg start_exclusive(); 3018edf8e2afSMika Westerberg } 3019edf8e2afSMika Westerberg 3020c3a92833Spbrook /* Assumes contents are already zeroed. */ 3021624f7979Spbrook void init_task_state(TaskState *ts) 3022624f7979Spbrook { 3023624f7979Spbrook int i; 3024624f7979Spbrook 3025624f7979Spbrook ts->used = 1; 3026624f7979Spbrook ts->first_free = ts->sigqueue_table; 3027624f7979Spbrook for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) { 3028624f7979Spbrook ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1]; 3029624f7979Spbrook } 3030624f7979Spbrook ts->sigqueue_table[i].next = NULL; 3031624f7979Spbrook } 30329de5e440Sbellard 3033fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg) 3034fc9c5412SJohannes Schauer { 3035fc9c5412SJohannes Schauer usage(); 3036fc9c5412SJohannes Schauer } 3037fc9c5412SJohannes Schauer 3038fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg) 3039fc9c5412SJohannes Schauer { 3040fc9c5412SJohannes Schauer int mask; 3041fc9c5412SJohannes Schauer const CPULogItem *item; 3042fc9c5412SJohannes Schauer 3043fc9c5412SJohannes Schauer mask = cpu_str_to_log_mask(arg); 3044fc9c5412SJohannes Schauer if (!mask) { 3045fc9c5412SJohannes Schauer printf("Log items (comma separated):\n"); 3046fc9c5412SJohannes Schauer for (item = cpu_log_items; item->mask != 0; item++) { 3047fc9c5412SJohannes Schauer printf("%-10s %s\n", item->name, item->help); 3048fc9c5412SJohannes Schauer } 3049fc9c5412SJohannes Schauer exit(1); 3050fc9c5412SJohannes Schauer } 3051fc9c5412SJohannes Schauer cpu_set_log(mask); 3052fc9c5412SJohannes Schauer } 3053fc9c5412SJohannes Schauer 305450171d42S陳韋任 static void handle_arg_log_filename(const char *arg) 305550171d42S陳韋任 { 305650171d42S陳韋任 cpu_set_log_filename(arg); 305750171d42S陳韋任 } 305850171d42S陳韋任 3059fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg) 3060fc9c5412SJohannes Schauer { 3061fc9c5412SJohannes Schauer char *r, *p, *token; 3062fc9c5412SJohannes Schauer r = p = strdup(arg); 3063fc9c5412SJohannes Schauer while ((token = strsep(&p, ",")) != NULL) { 3064fc9c5412SJohannes Schauer if (envlist_setenv(envlist, token) != 0) { 3065fc9c5412SJohannes Schauer usage(); 3066fc9c5412SJohannes Schauer } 3067fc9c5412SJohannes Schauer } 3068fc9c5412SJohannes Schauer free(r); 3069fc9c5412SJohannes Schauer } 3070fc9c5412SJohannes Schauer 3071fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg) 3072fc9c5412SJohannes Schauer { 3073fc9c5412SJohannes Schauer char *r, *p, *token; 3074fc9c5412SJohannes Schauer r = p = strdup(arg); 3075fc9c5412SJohannes Schauer while ((token = strsep(&p, ",")) != NULL) { 3076fc9c5412SJohannes Schauer if (envlist_unsetenv(envlist, token) != 0) { 3077fc9c5412SJohannes Schauer usage(); 3078fc9c5412SJohannes Schauer } 3079fc9c5412SJohannes Schauer } 3080fc9c5412SJohannes Schauer free(r); 3081fc9c5412SJohannes Schauer } 3082fc9c5412SJohannes Schauer 3083fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg) 3084fc9c5412SJohannes Schauer { 3085fc9c5412SJohannes Schauer argv0 = strdup(arg); 3086fc9c5412SJohannes Schauer } 3087fc9c5412SJohannes Schauer 3088fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg) 3089fc9c5412SJohannes Schauer { 3090fc9c5412SJohannes Schauer char *p; 3091fc9c5412SJohannes Schauer guest_stack_size = strtoul(arg, &p, 0); 3092fc9c5412SJohannes Schauer if (guest_stack_size == 0) { 3093fc9c5412SJohannes Schauer usage(); 3094fc9c5412SJohannes Schauer } 3095fc9c5412SJohannes Schauer 3096fc9c5412SJohannes Schauer if (*p == 'M') { 3097fc9c5412SJohannes Schauer guest_stack_size *= 1024 * 1024; 3098fc9c5412SJohannes Schauer } else if (*p == 'k' || *p == 'K') { 3099fc9c5412SJohannes Schauer guest_stack_size *= 1024; 3100fc9c5412SJohannes Schauer } 3101fc9c5412SJohannes Schauer } 3102fc9c5412SJohannes Schauer 3103fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg) 3104fc9c5412SJohannes Schauer { 3105fc9c5412SJohannes Schauer interp_prefix = strdup(arg); 3106fc9c5412SJohannes Schauer } 3107fc9c5412SJohannes Schauer 3108fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg) 3109fc9c5412SJohannes Schauer { 3110fc9c5412SJohannes Schauer qemu_host_page_size = atoi(arg); 3111fc9c5412SJohannes Schauer if (qemu_host_page_size == 0 || 3112fc9c5412SJohannes Schauer (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) { 3113fc9c5412SJohannes Schauer fprintf(stderr, "page size must be a power of two\n"); 3114fc9c5412SJohannes Schauer exit(1); 3115fc9c5412SJohannes Schauer } 3116fc9c5412SJohannes Schauer } 3117fc9c5412SJohannes Schauer 3118fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg) 3119fc9c5412SJohannes Schauer { 3120fc9c5412SJohannes Schauer gdbstub_port = atoi(arg); 3121fc9c5412SJohannes Schauer } 3122fc9c5412SJohannes Schauer 3123fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg) 3124fc9c5412SJohannes Schauer { 3125fc9c5412SJohannes Schauer qemu_uname_release = strdup(arg); 3126fc9c5412SJohannes Schauer } 3127fc9c5412SJohannes Schauer 3128fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg) 3129fc9c5412SJohannes Schauer { 3130fc9c5412SJohannes Schauer cpu_model = strdup(arg); 3131c8057f95SPeter Maydell if (cpu_model == NULL || is_help_option(cpu_model)) { 3132fc9c5412SJohannes Schauer /* XXX: implement xxx_cpu_list for targets that still miss it */ 3133e916cbf8SPeter Maydell #if defined(cpu_list) 3134e916cbf8SPeter Maydell cpu_list(stdout, &fprintf); 3135fc9c5412SJohannes Schauer #endif 3136fc9c5412SJohannes Schauer exit(1); 3137fc9c5412SJohannes Schauer } 3138fc9c5412SJohannes Schauer } 3139fc9c5412SJohannes Schauer 3140fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE) 3141fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg) 3142fc9c5412SJohannes Schauer { 3143fc9c5412SJohannes Schauer guest_base = strtol(arg, NULL, 0); 3144fc9c5412SJohannes Schauer have_guest_base = 1; 3145fc9c5412SJohannes Schauer } 3146fc9c5412SJohannes Schauer 3147fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg) 3148fc9c5412SJohannes Schauer { 3149fc9c5412SJohannes Schauer char *p; 3150fc9c5412SJohannes Schauer int shift = 0; 3151fc9c5412SJohannes Schauer reserved_va = strtoul(arg, &p, 0); 3152fc9c5412SJohannes Schauer switch (*p) { 3153fc9c5412SJohannes Schauer case 'k': 3154fc9c5412SJohannes Schauer case 'K': 3155fc9c5412SJohannes Schauer shift = 10; 3156fc9c5412SJohannes Schauer break; 3157fc9c5412SJohannes Schauer case 'M': 3158fc9c5412SJohannes Schauer shift = 20; 3159fc9c5412SJohannes Schauer break; 3160fc9c5412SJohannes Schauer case 'G': 3161fc9c5412SJohannes Schauer shift = 30; 3162fc9c5412SJohannes Schauer break; 3163fc9c5412SJohannes Schauer } 3164fc9c5412SJohannes Schauer if (shift) { 3165fc9c5412SJohannes Schauer unsigned long unshifted = reserved_va; 3166fc9c5412SJohannes Schauer p++; 3167fc9c5412SJohannes Schauer reserved_va <<= shift; 3168fc9c5412SJohannes Schauer if (((reserved_va >> shift) != unshifted) 3169fc9c5412SJohannes Schauer #if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS 3170fc9c5412SJohannes Schauer || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) 3171fc9c5412SJohannes Schauer #endif 3172fc9c5412SJohannes Schauer ) { 3173fc9c5412SJohannes Schauer fprintf(stderr, "Reserved virtual address too big\n"); 3174fc9c5412SJohannes Schauer exit(1); 3175fc9c5412SJohannes Schauer } 3176fc9c5412SJohannes Schauer } 3177fc9c5412SJohannes Schauer if (*p) { 3178fc9c5412SJohannes Schauer fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p); 3179fc9c5412SJohannes Schauer exit(1); 3180fc9c5412SJohannes Schauer } 3181fc9c5412SJohannes Schauer } 3182fc9c5412SJohannes Schauer #endif 3183fc9c5412SJohannes Schauer 3184fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg) 3185fc9c5412SJohannes Schauer { 3186fc9c5412SJohannes Schauer singlestep = 1; 3187fc9c5412SJohannes Schauer } 3188fc9c5412SJohannes Schauer 3189fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg) 3190fc9c5412SJohannes Schauer { 3191fc9c5412SJohannes Schauer do_strace = 1; 3192fc9c5412SJohannes Schauer } 3193fc9c5412SJohannes Schauer 3194fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg) 3195fc9c5412SJohannes Schauer { 3196fc9c5412SJohannes Schauer printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION 3197fc9c5412SJohannes Schauer ", Copyright (c) 2003-2008 Fabrice Bellard\n"); 31981386d4c0SPeter Maydell exit(0); 3199fc9c5412SJohannes Schauer } 3200fc9c5412SJohannes Schauer 3201fc9c5412SJohannes Schauer struct qemu_argument { 3202fc9c5412SJohannes Schauer const char *argv; 3203fc9c5412SJohannes Schauer const char *env; 3204fc9c5412SJohannes Schauer bool has_arg; 3205fc9c5412SJohannes Schauer void (*handle_opt)(const char *arg); 3206fc9c5412SJohannes Schauer const char *example; 3207fc9c5412SJohannes Schauer const char *help; 3208fc9c5412SJohannes Schauer }; 3209fc9c5412SJohannes Schauer 321042644ceeSJim Meyering static const struct qemu_argument arg_table[] = { 3211fc9c5412SJohannes Schauer {"h", "", false, handle_arg_help, 3212fc9c5412SJohannes Schauer "", "print this help"}, 3213fc9c5412SJohannes Schauer {"g", "QEMU_GDB", true, handle_arg_gdb, 3214fc9c5412SJohannes Schauer "port", "wait gdb connection to 'port'"}, 3215fc9c5412SJohannes Schauer {"L", "QEMU_LD_PREFIX", true, handle_arg_ld_prefix, 3216fc9c5412SJohannes Schauer "path", "set the elf interpreter prefix to 'path'"}, 3217fc9c5412SJohannes Schauer {"s", "QEMU_STACK_SIZE", true, handle_arg_stack_size, 3218fc9c5412SJohannes Schauer "size", "set the stack size to 'size' bytes"}, 3219fc9c5412SJohannes Schauer {"cpu", "QEMU_CPU", true, handle_arg_cpu, 3220c8057f95SPeter Maydell "model", "select CPU (-cpu help for list)"}, 3221fc9c5412SJohannes Schauer {"E", "QEMU_SET_ENV", true, handle_arg_set_env, 3222fc9c5412SJohannes Schauer "var=value", "sets targets environment variable (see below)"}, 3223fc9c5412SJohannes Schauer {"U", "QEMU_UNSET_ENV", true, handle_arg_unset_env, 3224fc9c5412SJohannes Schauer "var", "unsets targets environment variable (see below)"}, 3225fc9c5412SJohannes Schauer {"0", "QEMU_ARGV0", true, handle_arg_argv0, 3226fc9c5412SJohannes Schauer "argv0", "forces target process argv[0] to be 'argv0'"}, 3227fc9c5412SJohannes Schauer {"r", "QEMU_UNAME", true, handle_arg_uname, 3228fc9c5412SJohannes Schauer "uname", "set qemu uname release string to 'uname'"}, 3229fc9c5412SJohannes Schauer #if defined(CONFIG_USE_GUEST_BASE) 3230fc9c5412SJohannes Schauer {"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base, 3231fc9c5412SJohannes Schauer "address", "set guest_base address to 'address'"}, 3232fc9c5412SJohannes Schauer {"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va, 3233fc9c5412SJohannes Schauer "size", "reserve 'size' bytes for guest virtual address space"}, 3234fc9c5412SJohannes Schauer #endif 3235fc9c5412SJohannes Schauer {"d", "QEMU_LOG", true, handle_arg_log, 3236fc9c5412SJohannes Schauer "options", "activate log"}, 323750171d42S陳韋任 {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename, 323850171d42S陳韋任 "logfile", "override default logfile location"}, 3239fc9c5412SJohannes Schauer {"p", "QEMU_PAGESIZE", true, handle_arg_pagesize, 3240fc9c5412SJohannes Schauer "pagesize", "set the host page size to 'pagesize'"}, 3241fc9c5412SJohannes Schauer {"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep, 3242fc9c5412SJohannes Schauer "", "run in singlestep mode"}, 3243fc9c5412SJohannes Schauer {"strace", "QEMU_STRACE", false, handle_arg_strace, 3244fc9c5412SJohannes Schauer "", "log system calls"}, 3245fc9c5412SJohannes Schauer {"version", "QEMU_VERSION", false, handle_arg_version, 32461386d4c0SPeter Maydell "", "display version information and exit"}, 3247fc9c5412SJohannes Schauer {NULL, NULL, false, NULL, NULL, NULL} 3248fc9c5412SJohannes Schauer }; 3249fc9c5412SJohannes Schauer 3250fc9c5412SJohannes Schauer static void usage(void) 3251fc9c5412SJohannes Schauer { 325242644ceeSJim Meyering const struct qemu_argument *arginfo; 3253fc9c5412SJohannes Schauer int maxarglen; 3254fc9c5412SJohannes Schauer int maxenvlen; 3255fc9c5412SJohannes Schauer 3256fc9c5412SJohannes Schauer printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n" 3257fc9c5412SJohannes Schauer "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n" 3258fc9c5412SJohannes Schauer "\n" 3259fc9c5412SJohannes Schauer "Options and associated environment variables:\n" 3260fc9c5412SJohannes Schauer "\n"); 3261fc9c5412SJohannes Schauer 3262fc9c5412SJohannes Schauer maxarglen = maxenvlen = 0; 3263fc9c5412SJohannes Schauer 3264fc9c5412SJohannes Schauer for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { 3265fc9c5412SJohannes Schauer if (strlen(arginfo->env) > maxenvlen) { 3266fc9c5412SJohannes Schauer maxenvlen = strlen(arginfo->env); 3267fc9c5412SJohannes Schauer } 3268fc9c5412SJohannes Schauer if (strlen(arginfo->argv) > maxarglen) { 3269fc9c5412SJohannes Schauer maxarglen = strlen(arginfo->argv); 3270fc9c5412SJohannes Schauer } 3271fc9c5412SJohannes Schauer } 3272fc9c5412SJohannes Schauer 3273fc9c5412SJohannes Schauer printf("%-*s%-*sDescription\n", maxarglen+3, "Argument", 3274fc9c5412SJohannes Schauer maxenvlen+1, "Env-variable"); 3275fc9c5412SJohannes Schauer 3276fc9c5412SJohannes Schauer for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { 3277fc9c5412SJohannes Schauer if (arginfo->has_arg) { 3278fc9c5412SJohannes Schauer printf("-%s %-*s %-*s %s\n", arginfo->argv, 3279fc9c5412SJohannes Schauer (int)(maxarglen-strlen(arginfo->argv)), arginfo->example, 3280fc9c5412SJohannes Schauer maxenvlen, arginfo->env, arginfo->help); 3281fc9c5412SJohannes Schauer } else { 3282fc9c5412SJohannes Schauer printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv, 3283fc9c5412SJohannes Schauer maxenvlen, arginfo->env, 3284fc9c5412SJohannes Schauer arginfo->help); 3285fc9c5412SJohannes Schauer } 3286fc9c5412SJohannes Schauer } 3287fc9c5412SJohannes Schauer 3288fc9c5412SJohannes Schauer printf("\n" 3289fc9c5412SJohannes Schauer "Defaults:\n" 3290fc9c5412SJohannes Schauer "QEMU_LD_PREFIX = %s\n" 3291fc9c5412SJohannes Schauer "QEMU_STACK_SIZE = %ld byte\n" 3292fc9c5412SJohannes Schauer "QEMU_LOG = %s\n", 3293fc9c5412SJohannes Schauer interp_prefix, 3294fc9c5412SJohannes Schauer guest_stack_size, 3295fc9c5412SJohannes Schauer DEBUG_LOGFILE); 3296fc9c5412SJohannes Schauer 3297fc9c5412SJohannes Schauer printf("\n" 3298fc9c5412SJohannes Schauer "You can use -E and -U options or the QEMU_SET_ENV and\n" 3299fc9c5412SJohannes Schauer "QEMU_UNSET_ENV environment variables to set and unset\n" 3300fc9c5412SJohannes Schauer "environment variables for the target process.\n" 3301fc9c5412SJohannes Schauer "It is possible to provide several variables by separating them\n" 3302fc9c5412SJohannes Schauer "by commas in getsubopt(3) style. Additionally it is possible to\n" 3303fc9c5412SJohannes Schauer "provide the -E and -U options multiple times.\n" 3304fc9c5412SJohannes Schauer "The following lines are equivalent:\n" 3305fc9c5412SJohannes Schauer " -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n" 3306fc9c5412SJohannes Schauer " -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n" 3307fc9c5412SJohannes Schauer " QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n" 3308fc9c5412SJohannes Schauer "Note that if you provide several changes to a single variable\n" 3309fc9c5412SJohannes Schauer "the last change will stay in effect.\n"); 3310fc9c5412SJohannes Schauer 3311fc9c5412SJohannes Schauer exit(1); 3312fc9c5412SJohannes Schauer } 3313fc9c5412SJohannes Schauer 3314fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv) 3315fc9c5412SJohannes Schauer { 3316fc9c5412SJohannes Schauer const char *r; 3317fc9c5412SJohannes Schauer int optind; 331842644ceeSJim Meyering const struct qemu_argument *arginfo; 3319fc9c5412SJohannes Schauer 3320fc9c5412SJohannes Schauer for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { 3321fc9c5412SJohannes Schauer if (arginfo->env == NULL) { 3322fc9c5412SJohannes Schauer continue; 3323fc9c5412SJohannes Schauer } 3324fc9c5412SJohannes Schauer 3325fc9c5412SJohannes Schauer r = getenv(arginfo->env); 3326fc9c5412SJohannes Schauer if (r != NULL) { 3327fc9c5412SJohannes Schauer arginfo->handle_opt(r); 3328fc9c5412SJohannes Schauer } 3329fc9c5412SJohannes Schauer } 3330fc9c5412SJohannes Schauer 3331fc9c5412SJohannes Schauer optind = 1; 3332fc9c5412SJohannes Schauer for (;;) { 3333fc9c5412SJohannes Schauer if (optind >= argc) { 3334fc9c5412SJohannes Schauer break; 3335fc9c5412SJohannes Schauer } 3336fc9c5412SJohannes Schauer r = argv[optind]; 3337fc9c5412SJohannes Schauer if (r[0] != '-') { 3338fc9c5412SJohannes Schauer break; 3339fc9c5412SJohannes Schauer } 3340fc9c5412SJohannes Schauer optind++; 3341fc9c5412SJohannes Schauer r++; 3342fc9c5412SJohannes Schauer if (!strcmp(r, "-")) { 3343fc9c5412SJohannes Schauer break; 3344fc9c5412SJohannes Schauer } 3345fc9c5412SJohannes Schauer 3346fc9c5412SJohannes Schauer for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) { 3347fc9c5412SJohannes Schauer if (!strcmp(r, arginfo->argv)) { 33481386d4c0SPeter Maydell if (arginfo->has_arg) { 3349fc9c5412SJohannes Schauer if (optind >= argc) { 3350fc9c5412SJohannes Schauer usage(); 3351fc9c5412SJohannes Schauer } 3352fc9c5412SJohannes Schauer arginfo->handle_opt(argv[optind]); 3353fc9c5412SJohannes Schauer optind++; 33541386d4c0SPeter Maydell } else { 33551386d4c0SPeter Maydell arginfo->handle_opt(NULL); 3356fc9c5412SJohannes Schauer } 3357fc9c5412SJohannes Schauer break; 3358fc9c5412SJohannes Schauer } 3359fc9c5412SJohannes Schauer } 3360fc9c5412SJohannes Schauer 3361fc9c5412SJohannes Schauer /* no option matched the current argv */ 3362fc9c5412SJohannes Schauer if (arginfo->handle_opt == NULL) { 3363fc9c5412SJohannes Schauer usage(); 3364fc9c5412SJohannes Schauer } 3365fc9c5412SJohannes Schauer } 3366fc9c5412SJohannes Schauer 3367fc9c5412SJohannes Schauer if (optind >= argc) { 3368fc9c5412SJohannes Schauer usage(); 3369fc9c5412SJohannes Schauer } 3370fc9c5412SJohannes Schauer 3371fc9c5412SJohannes Schauer filename = argv[optind]; 3372fc9c5412SJohannes Schauer exec_path = argv[optind]; 3373fc9c5412SJohannes Schauer 3374fc9c5412SJohannes Schauer return optind; 3375fc9c5412SJohannes Schauer } 3376fc9c5412SJohannes Schauer 3377902b3d5cSmalc int main(int argc, char **argv, char **envp) 337831e31b8aSbellard { 3379c235d738SMatthew Fernandez const char *log_file = DEBUG_LOGFILE; 338001ffc75bSbellard struct target_pt_regs regs1, *regs = ®s1; 338131e31b8aSbellard struct image_info info1, *info = &info1; 3382edf8e2afSMika Westerberg struct linux_binprm bprm; 338348e15fc2SNathan Froyd TaskState *ts; 33849349b4f9SAndreas Färber CPUArchState *env; 3385586314f2Sbellard int optind; 338604a6dfebSaurel32 char **target_environ, **wrk; 33877d8cec95Saurel32 char **target_argv; 33887d8cec95Saurel32 int target_argc; 33897d8cec95Saurel32 int i; 3390fd4d81ddSArnaud Patard int ret; 339131e31b8aSbellard 3392ce008c1fSAndreas Färber module_call_init(MODULE_INIT_QOM); 3393ce008c1fSAndreas Färber 3394902b3d5cSmalc qemu_cache_utils_init(envp); 3395902b3d5cSmalc 339604a6dfebSaurel32 if ((envlist = envlist_create()) == NULL) { 339704a6dfebSaurel32 (void) fprintf(stderr, "Unable to allocate envlist\n"); 339804a6dfebSaurel32 exit(1); 339904a6dfebSaurel32 } 340004a6dfebSaurel32 340104a6dfebSaurel32 /* add current environment into the list */ 340204a6dfebSaurel32 for (wrk = environ; *wrk != NULL; wrk++) { 340304a6dfebSaurel32 (void) envlist_setenv(envlist, *wrk); 340404a6dfebSaurel32 } 340504a6dfebSaurel32 3406703e0e89SRichard Henderson /* Read the stack limit from the kernel. If it's "unlimited", 3407703e0e89SRichard Henderson then we can do little else besides use the default. */ 3408703e0e89SRichard Henderson { 3409703e0e89SRichard Henderson struct rlimit lim; 3410703e0e89SRichard Henderson if (getrlimit(RLIMIT_STACK, &lim) == 0 341181bbe906Stakasi-y@ops.dti.ne.jp && lim.rlim_cur != RLIM_INFINITY 341281bbe906Stakasi-y@ops.dti.ne.jp && lim.rlim_cur == (target_long)lim.rlim_cur) { 3413703e0e89SRichard Henderson guest_stack_size = lim.rlim_cur; 3414703e0e89SRichard Henderson } 3415703e0e89SRichard Henderson } 3416703e0e89SRichard Henderson 3417b1f9be31Sj_mayer cpu_model = NULL; 3418b5ec5ce0Sjohn cooper #if defined(cpudef_setup) 3419b5ec5ce0Sjohn cooper cpudef_setup(); /* parse cpu definitions in target config file (TBD) */ 3420b5ec5ce0Sjohn cooper #endif 3421b5ec5ce0Sjohn cooper 3422c235d738SMatthew Fernandez /* init debug */ 3423c235d738SMatthew Fernandez cpu_set_log_filename(log_file); 3424fc9c5412SJohannes Schauer optind = parse_args(argc, argv); 34254b5dfd82SPeter Maydell 342631e31b8aSbellard /* Zero out regs */ 342701ffc75bSbellard memset(regs, 0, sizeof(struct target_pt_regs)); 342831e31b8aSbellard 342931e31b8aSbellard /* Zero out image_info */ 343031e31b8aSbellard memset(info, 0, sizeof(struct image_info)); 343131e31b8aSbellard 3432edf8e2afSMika Westerberg memset(&bprm, 0, sizeof (bprm)); 3433edf8e2afSMika Westerberg 343474cd30b8Sbellard /* Scan interp_prefix dir for replacement files. */ 343574cd30b8Sbellard init_paths(interp_prefix); 343674cd30b8Sbellard 343746027c07Sbellard if (cpu_model == NULL) { 3438aaed909aSbellard #if defined(TARGET_I386) 343946027c07Sbellard #ifdef TARGET_X86_64 344046027c07Sbellard cpu_model = "qemu64"; 344146027c07Sbellard #else 344246027c07Sbellard cpu_model = "qemu32"; 344346027c07Sbellard #endif 3444aaed909aSbellard #elif defined(TARGET_ARM) 3445088ab16cSpbrook cpu_model = "any"; 3446d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32) 3447d2fbca94SGuan Xuetao cpu_model = "any"; 3448aaed909aSbellard #elif defined(TARGET_M68K) 3449aaed909aSbellard cpu_model = "any"; 3450aaed909aSbellard #elif defined(TARGET_SPARC) 3451aaed909aSbellard #ifdef TARGET_SPARC64 3452aaed909aSbellard cpu_model = "TI UltraSparc II"; 3453aaed909aSbellard #else 3454aaed909aSbellard cpu_model = "Fujitsu MB86904"; 345546027c07Sbellard #endif 3456aaed909aSbellard #elif defined(TARGET_MIPS) 3457aaed909aSbellard #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) 3458aaed909aSbellard cpu_model = "20Kc"; 3459aaed909aSbellard #else 3460aaed909aSbellard cpu_model = "24Kf"; 3461aaed909aSbellard #endif 3462d962783eSJia Liu #elif defined TARGET_OPENRISC 3463d962783eSJia Liu cpu_model = "or1200"; 3464aaed909aSbellard #elif defined(TARGET_PPC) 34657ded4f52Sbellard #ifdef TARGET_PPC64 3466f7177937SAurelien Jarno cpu_model = "970fx"; 34677ded4f52Sbellard #else 3468aaed909aSbellard cpu_model = "750"; 34697ded4f52Sbellard #endif 3470aaed909aSbellard #else 3471aaed909aSbellard cpu_model = "any"; 3472aaed909aSbellard #endif 3473aaed909aSbellard } 3474d5ab9713SJan Kiszka tcg_exec_init(0); 3475d5ab9713SJan Kiszka cpu_exec_init_all(); 347683fb7adfSbellard /* NOTE: we need to init the CPU at this stage to get 347783fb7adfSbellard qemu_host_page_size */ 3478aaed909aSbellard env = cpu_init(cpu_model); 3479aaed909aSbellard if (!env) { 3480aaed909aSbellard fprintf(stderr, "Unable to find CPU definition\n"); 3481aaed909aSbellard exit(1); 3482aaed909aSbellard } 3483b55a37c9SBlue Swirl #if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) 3484ff18b762SAndreas Färber cpu_reset(ENV_GET_CPU(env)); 3485b55a37c9SBlue Swirl #endif 3486b55a37c9SBlue Swirl 3487d5975363Spbrook thread_env = env; 348854936004Sbellard 3489b92c47c1Sths if (getenv("QEMU_STRACE")) { 3490b92c47c1Sths do_strace = 1; 3491b92c47c1Sths } 3492b92c47c1Sths 349304a6dfebSaurel32 target_environ = envlist_to_environ(envlist, NULL); 349404a6dfebSaurel32 envlist_free(envlist); 3495b12b6a18Sths 3496379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE) 3497379f6698SPaul Brook /* 3498379f6698SPaul Brook * Now that page sizes are configured in cpu_init() we can do 3499379f6698SPaul Brook * proper page alignment for guest_base. 3500379f6698SPaul Brook */ 3501379f6698SPaul Brook guest_base = HOST_PAGE_ALIGN(guest_base); 350268a1c816SPaul Brook 350397cc7560SDr. David Alan Gilbert if (reserved_va || have_guest_base) { 3504806d1021SMeador Inge guest_base = init_guest_space(guest_base, reserved_va, 0, 3505806d1021SMeador Inge have_guest_base); 3506806d1021SMeador Inge if (guest_base == (unsigned long)-1) { 3507097b8cb8SPeter Maydell fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address " 3508097b8cb8SPeter Maydell "space for use as guest address space (check your virtual " 3509097b8cb8SPeter Maydell "memory ulimit setting or reserve less using -R option)\n", 3510097b8cb8SPeter Maydell reserved_va); 351197cc7560SDr. David Alan Gilbert exit(1); 351297cc7560SDr. David Alan Gilbert } 3513806d1021SMeador Inge 3514806d1021SMeador Inge if (reserved_va) { 3515806d1021SMeador Inge mmap_next_start = reserved_va; 3516806d1021SMeador Inge } 351797cc7560SDr. David Alan Gilbert } 351814f24e14SRichard Henderson #endif /* CONFIG_USE_GUEST_BASE */ 3519379f6698SPaul Brook 3520379f6698SPaul Brook /* 3521379f6698SPaul Brook * Read in mmap_min_addr kernel parameter. This value is used 3522379f6698SPaul Brook * When loading the ELF image to determine whether guest_base 352314f24e14SRichard Henderson * is needed. It is also used in mmap_find_vma. 3524379f6698SPaul Brook */ 352514f24e14SRichard Henderson { 3526379f6698SPaul Brook FILE *fp; 3527379f6698SPaul Brook 3528379f6698SPaul Brook if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { 3529379f6698SPaul Brook unsigned long tmp; 3530379f6698SPaul Brook if (fscanf(fp, "%lu", &tmp) == 1) { 3531379f6698SPaul Brook mmap_min_addr = tmp; 3532379f6698SPaul Brook qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr); 3533379f6698SPaul Brook } 3534379f6698SPaul Brook fclose(fp); 3535379f6698SPaul Brook } 3536379f6698SPaul Brook } 3537379f6698SPaul Brook 35387d8cec95Saurel32 /* 35397d8cec95Saurel32 * Prepare copy of argv vector for target. 35407d8cec95Saurel32 */ 35417d8cec95Saurel32 target_argc = argc - optind; 35427d8cec95Saurel32 target_argv = calloc(target_argc + 1, sizeof (char *)); 35437d8cec95Saurel32 if (target_argv == NULL) { 35447d8cec95Saurel32 (void) fprintf(stderr, "Unable to allocate memory for target_argv\n"); 35457d8cec95Saurel32 exit(1); 35467d8cec95Saurel32 } 35477d8cec95Saurel32 35487d8cec95Saurel32 /* 35497d8cec95Saurel32 * If argv0 is specified (using '-0' switch) we replace 35507d8cec95Saurel32 * argv[0] pointer with the given one. 35517d8cec95Saurel32 */ 35527d8cec95Saurel32 i = 0; 35537d8cec95Saurel32 if (argv0 != NULL) { 35547d8cec95Saurel32 target_argv[i++] = strdup(argv0); 35557d8cec95Saurel32 } 35567d8cec95Saurel32 for (; i < target_argc; i++) { 35577d8cec95Saurel32 target_argv[i] = strdup(argv[optind + i]); 35587d8cec95Saurel32 } 35597d8cec95Saurel32 target_argv[target_argc] = NULL; 35607d8cec95Saurel32 35617267c094SAnthony Liguori ts = g_malloc0 (sizeof(TaskState)); 3562edf8e2afSMika Westerberg init_task_state(ts); 3563edf8e2afSMika Westerberg /* build Task State */ 3564edf8e2afSMika Westerberg ts->info = info; 3565edf8e2afSMika Westerberg ts->bprm = &bprm; 3566edf8e2afSMika Westerberg env->opaque = ts; 3567edf8e2afSMika Westerberg task_settid(ts); 3568edf8e2afSMika Westerberg 3569fd4d81ddSArnaud Patard ret = loader_exec(filename, target_argv, target_environ, regs, 3570fd4d81ddSArnaud Patard info, &bprm); 3571fd4d81ddSArnaud Patard if (ret != 0) { 3572*885c1d10SPeter Maydell printf("Error while loading %s: %s\n", filename, strerror(-ret)); 357374cd30b8Sbellard _exit(1); 357431e31b8aSbellard } 357531e31b8aSbellard 3576b12b6a18Sths for (wrk = target_environ; *wrk; wrk++) { 3577b12b6a18Sths free(*wrk); 3578b12b6a18Sths } 3579b12b6a18Sths 3580b12b6a18Sths free(target_environ); 3581b12b6a18Sths 35822e77eac6Sblueswir1 if (qemu_log_enabled()) { 3583379f6698SPaul Brook #if defined(CONFIG_USE_GUEST_BASE) 3584379f6698SPaul Brook qemu_log("guest_base 0x%lx\n", guest_base); 3585379f6698SPaul Brook #endif 358693fcfe39Saliguori log_page_dump(); 358754936004Sbellard 358893fcfe39Saliguori qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); 358993fcfe39Saliguori qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code); 359093fcfe39Saliguori qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n", 35913d177870Sj_mayer info->start_code); 359293fcfe39Saliguori qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n", 35933d177870Sj_mayer info->start_data); 359493fcfe39Saliguori qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data); 359593fcfe39Saliguori qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", 35963d177870Sj_mayer info->start_stack); 359793fcfe39Saliguori qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk); 359893fcfe39Saliguori qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry); 35992e77eac6Sblueswir1 } 360031e31b8aSbellard 360153a5960aSpbrook target_set_brk(info->brk); 360231e31b8aSbellard syscall_init(); 360366fb9763Sbellard signal_init(); 360431e31b8aSbellard 36059002ec79SRichard Henderson #if defined(CONFIG_USE_GUEST_BASE) 36069002ec79SRichard Henderson /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay 36079002ec79SRichard Henderson generating the prologue until now so that the prologue can take 36089002ec79SRichard Henderson the real value of GUEST_BASE into account. */ 36099002ec79SRichard Henderson tcg_prologue_init(&tcg_ctx); 36109002ec79SRichard Henderson #endif 36119002ec79SRichard Henderson 3612b346ff46Sbellard #if defined(TARGET_I386) 36132e255c6bSbellard cpu_x86_set_cpl(env, 3); 36142e255c6bSbellard 36153802ce26Sbellard env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; 36161bde465eSbellard env->hflags |= HF_PE_MASK; 36171bde465eSbellard if (env->cpuid_features & CPUID_SSE) { 36181bde465eSbellard env->cr[4] |= CR4_OSFXSR_MASK; 36191bde465eSbellard env->hflags |= HF_OSFXSR_MASK; 36201bde465eSbellard } 3621d2fd1af7Sbellard #ifndef TARGET_ABI32 36224dbc422bSbellard /* enable 64 bit mode if possible */ 36234dbc422bSbellard if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) { 36244dbc422bSbellard fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); 36254dbc422bSbellard exit(1); 36264dbc422bSbellard } 3627d2fd1af7Sbellard env->cr[4] |= CR4_PAE_MASK; 36284dbc422bSbellard env->efer |= MSR_EFER_LMA | MSR_EFER_LME; 3629d2fd1af7Sbellard env->hflags |= HF_LMA_MASK; 3630d2fd1af7Sbellard #endif 36313802ce26Sbellard 3632415e561fSbellard /* flags setup : we activate the IRQs by default as in user mode */ 3633415e561fSbellard env->eflags |= IF_MASK; 3634415e561fSbellard 36356dbad63eSbellard /* linux register setup */ 3636d2fd1af7Sbellard #ifndef TARGET_ABI32 363784409ddbSj_mayer env->regs[R_EAX] = regs->rax; 363884409ddbSj_mayer env->regs[R_EBX] = regs->rbx; 363984409ddbSj_mayer env->regs[R_ECX] = regs->rcx; 364084409ddbSj_mayer env->regs[R_EDX] = regs->rdx; 364184409ddbSj_mayer env->regs[R_ESI] = regs->rsi; 364284409ddbSj_mayer env->regs[R_EDI] = regs->rdi; 364384409ddbSj_mayer env->regs[R_EBP] = regs->rbp; 364484409ddbSj_mayer env->regs[R_ESP] = regs->rsp; 364584409ddbSj_mayer env->eip = regs->rip; 364684409ddbSj_mayer #else 36470ecfa993Sbellard env->regs[R_EAX] = regs->eax; 36480ecfa993Sbellard env->regs[R_EBX] = regs->ebx; 36490ecfa993Sbellard env->regs[R_ECX] = regs->ecx; 36500ecfa993Sbellard env->regs[R_EDX] = regs->edx; 36510ecfa993Sbellard env->regs[R_ESI] = regs->esi; 36520ecfa993Sbellard env->regs[R_EDI] = regs->edi; 36530ecfa993Sbellard env->regs[R_EBP] = regs->ebp; 36540ecfa993Sbellard env->regs[R_ESP] = regs->esp; 3655dab2ed99Sbellard env->eip = regs->eip; 365684409ddbSj_mayer #endif 365731e31b8aSbellard 3658f4beb510Sbellard /* linux interrupt setup */ 3659e441570fSbalrog #ifndef TARGET_ABI32 3660e441570fSbalrog env->idt.limit = 511; 3661e441570fSbalrog #else 3662e441570fSbalrog env->idt.limit = 255; 3663e441570fSbalrog #endif 3664e441570fSbalrog env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), 3665e441570fSbalrog PROT_READ|PROT_WRITE, 3666e441570fSbalrog MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 3667e441570fSbalrog idt_table = g2h(env->idt.base); 3668f4beb510Sbellard set_idt(0, 0); 3669f4beb510Sbellard set_idt(1, 0); 3670f4beb510Sbellard set_idt(2, 0); 3671f4beb510Sbellard set_idt(3, 3); 3672f4beb510Sbellard set_idt(4, 3); 3673ec95da6cSbellard set_idt(5, 0); 3674f4beb510Sbellard set_idt(6, 0); 3675f4beb510Sbellard set_idt(7, 0); 3676f4beb510Sbellard set_idt(8, 0); 3677f4beb510Sbellard set_idt(9, 0); 3678f4beb510Sbellard set_idt(10, 0); 3679f4beb510Sbellard set_idt(11, 0); 3680f4beb510Sbellard set_idt(12, 0); 3681f4beb510Sbellard set_idt(13, 0); 3682f4beb510Sbellard set_idt(14, 0); 3683f4beb510Sbellard set_idt(15, 0); 3684f4beb510Sbellard set_idt(16, 0); 3685f4beb510Sbellard set_idt(17, 0); 3686f4beb510Sbellard set_idt(18, 0); 3687f4beb510Sbellard set_idt(19, 0); 3688f4beb510Sbellard set_idt(0x80, 3); 3689f4beb510Sbellard 36906dbad63eSbellard /* linux segment setup */ 36918d18e893Sbellard { 36928d18e893Sbellard uint64_t *gdt_table; 3693e441570fSbalrog env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, 3694e441570fSbalrog PROT_READ|PROT_WRITE, 3695e441570fSbalrog MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 36968d18e893Sbellard env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; 3697e441570fSbalrog gdt_table = g2h(env->gdt.base); 3698d2fd1af7Sbellard #ifdef TARGET_ABI32 3699f4beb510Sbellard write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 3700f4beb510Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 3701f4beb510Sbellard (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 3702d2fd1af7Sbellard #else 3703d2fd1af7Sbellard /* 64 bit code segment */ 3704d2fd1af7Sbellard write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 3705d2fd1af7Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 3706d2fd1af7Sbellard DESC_L_MASK | 3707d2fd1af7Sbellard (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 3708d2fd1af7Sbellard #endif 3709f4beb510Sbellard write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, 3710f4beb510Sbellard DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 3711f4beb510Sbellard (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); 37128d18e893Sbellard } 37136dbad63eSbellard cpu_x86_load_seg(env, R_CS, __USER_CS); 3714d2fd1af7Sbellard cpu_x86_load_seg(env, R_SS, __USER_DS); 3715d2fd1af7Sbellard #ifdef TARGET_ABI32 37166dbad63eSbellard cpu_x86_load_seg(env, R_DS, __USER_DS); 37176dbad63eSbellard cpu_x86_load_seg(env, R_ES, __USER_DS); 37186dbad63eSbellard cpu_x86_load_seg(env, R_FS, __USER_DS); 37196dbad63eSbellard cpu_x86_load_seg(env, R_GS, __USER_DS); 3720d6eb40f6Sths /* This hack makes Wine work... */ 3721d6eb40f6Sths env->segs[R_FS].selector = 0; 3722d2fd1af7Sbellard #else 3723d2fd1af7Sbellard cpu_x86_load_seg(env, R_DS, 0); 3724d2fd1af7Sbellard cpu_x86_load_seg(env, R_ES, 0); 3725d2fd1af7Sbellard cpu_x86_load_seg(env, R_FS, 0); 3726d2fd1af7Sbellard cpu_x86_load_seg(env, R_GS, 0); 3727d2fd1af7Sbellard #endif 3728b346ff46Sbellard #elif defined(TARGET_ARM) 3729b346ff46Sbellard { 3730b346ff46Sbellard int i; 3731b5ff1b31Sbellard cpsr_write(env, regs->uregs[16], 0xffffffff); 3732b346ff46Sbellard for(i = 0; i < 16; i++) { 3733b346ff46Sbellard env->regs[i] = regs->uregs[i]; 3734b346ff46Sbellard } 3735d8fd2954SPaul Brook /* Enable BE8. */ 3736d8fd2954SPaul Brook if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4 3737d8fd2954SPaul Brook && (info->elf_flags & EF_ARM_BE8)) { 3738d8fd2954SPaul Brook env->bswap_code = 1; 3739d8fd2954SPaul Brook } 3740b346ff46Sbellard } 3741d2fbca94SGuan Xuetao #elif defined(TARGET_UNICORE32) 3742d2fbca94SGuan Xuetao { 3743d2fbca94SGuan Xuetao int i; 3744d2fbca94SGuan Xuetao cpu_asr_write(env, regs->uregs[32], 0xffffffff); 3745d2fbca94SGuan Xuetao for (i = 0; i < 32; i++) { 3746d2fbca94SGuan Xuetao env->regs[i] = regs->uregs[i]; 3747d2fbca94SGuan Xuetao } 3748d2fbca94SGuan Xuetao } 374993ac68bcSbellard #elif defined(TARGET_SPARC) 3750060366c5Sbellard { 3751060366c5Sbellard int i; 3752060366c5Sbellard env->pc = regs->pc; 3753060366c5Sbellard env->npc = regs->npc; 3754060366c5Sbellard env->y = regs->y; 3755060366c5Sbellard for(i = 0; i < 8; i++) 3756060366c5Sbellard env->gregs[i] = regs->u_regs[i]; 3757060366c5Sbellard for(i = 0; i < 8; i++) 3758060366c5Sbellard env->regwptr[i] = regs->u_regs[i + 8]; 3759060366c5Sbellard } 376067867308Sbellard #elif defined(TARGET_PPC) 376167867308Sbellard { 376267867308Sbellard int i; 37633fc6c082Sbellard 37640411a972Sj_mayer #if defined(TARGET_PPC64) 37650411a972Sj_mayer #if defined(TARGET_ABI32) 37660411a972Sj_mayer env->msr &= ~((target_ulong)1 << MSR_SF); 3767e85e7c6eSj_mayer #else 37680411a972Sj_mayer env->msr |= (target_ulong)1 << MSR_SF; 37690411a972Sj_mayer #endif 377084409ddbSj_mayer #endif 377167867308Sbellard env->nip = regs->nip; 377267867308Sbellard for(i = 0; i < 32; i++) { 377367867308Sbellard env->gpr[i] = regs->gpr[i]; 377467867308Sbellard } 377567867308Sbellard } 3776e6e5906bSpbrook #elif defined(TARGET_M68K) 3777e6e5906bSpbrook { 3778e6e5906bSpbrook env->pc = regs->pc; 3779e6e5906bSpbrook env->dregs[0] = regs->d0; 3780e6e5906bSpbrook env->dregs[1] = regs->d1; 3781e6e5906bSpbrook env->dregs[2] = regs->d2; 3782e6e5906bSpbrook env->dregs[3] = regs->d3; 3783e6e5906bSpbrook env->dregs[4] = regs->d4; 3784e6e5906bSpbrook env->dregs[5] = regs->d5; 3785e6e5906bSpbrook env->dregs[6] = regs->d6; 3786e6e5906bSpbrook env->dregs[7] = regs->d7; 3787e6e5906bSpbrook env->aregs[0] = regs->a0; 3788e6e5906bSpbrook env->aregs[1] = regs->a1; 3789e6e5906bSpbrook env->aregs[2] = regs->a2; 3790e6e5906bSpbrook env->aregs[3] = regs->a3; 3791e6e5906bSpbrook env->aregs[4] = regs->a4; 3792e6e5906bSpbrook env->aregs[5] = regs->a5; 3793e6e5906bSpbrook env->aregs[6] = regs->a6; 3794e6e5906bSpbrook env->aregs[7] = regs->usp; 3795e6e5906bSpbrook env->sr = regs->sr; 3796e6e5906bSpbrook ts->sim_syscalls = 1; 3797e6e5906bSpbrook } 3798b779e29eSEdgar E. Iglesias #elif defined(TARGET_MICROBLAZE) 3799b779e29eSEdgar E. Iglesias { 3800b779e29eSEdgar E. Iglesias env->regs[0] = regs->r0; 3801b779e29eSEdgar E. Iglesias env->regs[1] = regs->r1; 3802b779e29eSEdgar E. Iglesias env->regs[2] = regs->r2; 3803b779e29eSEdgar E. Iglesias env->regs[3] = regs->r3; 3804b779e29eSEdgar E. Iglesias env->regs[4] = regs->r4; 3805b779e29eSEdgar E. Iglesias env->regs[5] = regs->r5; 3806b779e29eSEdgar E. Iglesias env->regs[6] = regs->r6; 3807b779e29eSEdgar E. Iglesias env->regs[7] = regs->r7; 3808b779e29eSEdgar E. Iglesias env->regs[8] = regs->r8; 3809b779e29eSEdgar E. Iglesias env->regs[9] = regs->r9; 3810b779e29eSEdgar E. Iglesias env->regs[10] = regs->r10; 3811b779e29eSEdgar E. Iglesias env->regs[11] = regs->r11; 3812b779e29eSEdgar E. Iglesias env->regs[12] = regs->r12; 3813b779e29eSEdgar E. Iglesias env->regs[13] = regs->r13; 3814b779e29eSEdgar E. Iglesias env->regs[14] = regs->r14; 3815b779e29eSEdgar E. Iglesias env->regs[15] = regs->r15; 3816b779e29eSEdgar E. Iglesias env->regs[16] = regs->r16; 3817b779e29eSEdgar E. Iglesias env->regs[17] = regs->r17; 3818b779e29eSEdgar E. Iglesias env->regs[18] = regs->r18; 3819b779e29eSEdgar E. Iglesias env->regs[19] = regs->r19; 3820b779e29eSEdgar E. Iglesias env->regs[20] = regs->r20; 3821b779e29eSEdgar E. Iglesias env->regs[21] = regs->r21; 3822b779e29eSEdgar E. Iglesias env->regs[22] = regs->r22; 3823b779e29eSEdgar E. Iglesias env->regs[23] = regs->r23; 3824b779e29eSEdgar E. Iglesias env->regs[24] = regs->r24; 3825b779e29eSEdgar E. Iglesias env->regs[25] = regs->r25; 3826b779e29eSEdgar E. Iglesias env->regs[26] = regs->r26; 3827b779e29eSEdgar E. Iglesias env->regs[27] = regs->r27; 3828b779e29eSEdgar E. Iglesias env->regs[28] = regs->r28; 3829b779e29eSEdgar E. Iglesias env->regs[29] = regs->r29; 3830b779e29eSEdgar E. Iglesias env->regs[30] = regs->r30; 3831b779e29eSEdgar E. Iglesias env->regs[31] = regs->r31; 3832b779e29eSEdgar E. Iglesias env->sregs[SR_PC] = regs->pc; 3833b779e29eSEdgar E. Iglesias } 3834048f6b4dSbellard #elif defined(TARGET_MIPS) 3835048f6b4dSbellard { 3836048f6b4dSbellard int i; 3837048f6b4dSbellard 3838048f6b4dSbellard for(i = 0; i < 32; i++) { 3839b5dc7732Sths env->active_tc.gpr[i] = regs->regs[i]; 3840048f6b4dSbellard } 38410fddbbf2SNathan Froyd env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1; 38420fddbbf2SNathan Froyd if (regs->cp0_epc & 1) { 38430fddbbf2SNathan Froyd env->hflags |= MIPS_HFLAG_M16; 38440fddbbf2SNathan Froyd } 3845048f6b4dSbellard } 3846d962783eSJia Liu #elif defined(TARGET_OPENRISC) 3847d962783eSJia Liu { 3848d962783eSJia Liu int i; 3849d962783eSJia Liu 3850d962783eSJia Liu for (i = 0; i < 32; i++) { 3851d962783eSJia Liu env->gpr[i] = regs->gpr[i]; 3852d962783eSJia Liu } 3853d962783eSJia Liu 3854d962783eSJia Liu env->sr = regs->sr; 3855d962783eSJia Liu env->pc = regs->pc; 3856d962783eSJia Liu } 3857fdf9b3e8Sbellard #elif defined(TARGET_SH4) 3858fdf9b3e8Sbellard { 3859fdf9b3e8Sbellard int i; 3860fdf9b3e8Sbellard 3861fdf9b3e8Sbellard for(i = 0; i < 16; i++) { 3862fdf9b3e8Sbellard env->gregs[i] = regs->regs[i]; 3863fdf9b3e8Sbellard } 3864fdf9b3e8Sbellard env->pc = regs->pc; 3865fdf9b3e8Sbellard } 38667a3148a9Sj_mayer #elif defined(TARGET_ALPHA) 38677a3148a9Sj_mayer { 38687a3148a9Sj_mayer int i; 38697a3148a9Sj_mayer 38707a3148a9Sj_mayer for(i = 0; i < 28; i++) { 3871992f48a0Sblueswir1 env->ir[i] = ((abi_ulong *)regs)[i]; 38727a3148a9Sj_mayer } 3873dad081eeSRichard Henderson env->ir[IR_SP] = regs->usp; 38747a3148a9Sj_mayer env->pc = regs->pc; 38757a3148a9Sj_mayer } 387648733d19Sths #elif defined(TARGET_CRIS) 387748733d19Sths { 387848733d19Sths env->regs[0] = regs->r0; 387948733d19Sths env->regs[1] = regs->r1; 388048733d19Sths env->regs[2] = regs->r2; 388148733d19Sths env->regs[3] = regs->r3; 388248733d19Sths env->regs[4] = regs->r4; 388348733d19Sths env->regs[5] = regs->r5; 388448733d19Sths env->regs[6] = regs->r6; 388548733d19Sths env->regs[7] = regs->r7; 388648733d19Sths env->regs[8] = regs->r8; 388748733d19Sths env->regs[9] = regs->r9; 388848733d19Sths env->regs[10] = regs->r10; 388948733d19Sths env->regs[11] = regs->r11; 389048733d19Sths env->regs[12] = regs->r12; 389148733d19Sths env->regs[13] = regs->r13; 389248733d19Sths env->regs[14] = info->start_stack; 389348733d19Sths env->regs[15] = regs->acr; 389448733d19Sths env->pc = regs->erp; 389548733d19Sths } 3896a4c075f1SUlrich Hecht #elif defined(TARGET_S390X) 3897a4c075f1SUlrich Hecht { 3898a4c075f1SUlrich Hecht int i; 3899a4c075f1SUlrich Hecht for (i = 0; i < 16; i++) { 3900a4c075f1SUlrich Hecht env->regs[i] = regs->gprs[i]; 3901a4c075f1SUlrich Hecht } 3902a4c075f1SUlrich Hecht env->psw.mask = regs->psw.mask; 3903a4c075f1SUlrich Hecht env->psw.addr = regs->psw.addr; 3904a4c075f1SUlrich Hecht } 3905b346ff46Sbellard #else 3906b346ff46Sbellard #error unsupported target CPU 3907b346ff46Sbellard #endif 390831e31b8aSbellard 3909d2fbca94SGuan Xuetao #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) 3910a87295e8Spbrook ts->stack_base = info->start_stack; 3911a87295e8Spbrook ts->heap_base = info->brk; 3912a87295e8Spbrook /* This will be filled in on the first SYS_HEAPINFO call. */ 3913a87295e8Spbrook ts->heap_limit = 0; 3914a87295e8Spbrook #endif 3915a87295e8Spbrook 391674c33bedSbellard if (gdbstub_port) { 3917ff7a981aSPeter Maydell if (gdbserver_start(gdbstub_port) < 0) { 3918ff7a981aSPeter Maydell fprintf(stderr, "qemu: could not open gdbserver on port %d\n", 3919ff7a981aSPeter Maydell gdbstub_port); 3920ff7a981aSPeter Maydell exit(1); 3921ff7a981aSPeter Maydell } 39221fddef4bSbellard gdb_handlesig(env, 0); 39231fddef4bSbellard } 39241b6b029eSbellard cpu_loop(env); 39251b6b029eSbellard /* never exits */ 392631e31b8aSbellard return 0; 392731e31b8aSbellard } 3928