No code change, only move code from main.c to ppc/cpu_loop.c. Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20180411185651.21351-7-laurent@vivier.eu>
		
			
				
	
	
		
			580 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			580 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 *  qemu user cpu loop
 | 
						|
 *
 | 
						|
 *  Copyright (c) 2003-2008 Fabrice Bellard
 | 
						|
 *
 | 
						|
 *  This program is free software; you can redistribute it and/or modify
 | 
						|
 *  it under the terms of the GNU General Public License as published by
 | 
						|
 *  the Free Software Foundation; either version 2 of the License, or
 | 
						|
 *  (at your option) any later version.
 | 
						|
 *
 | 
						|
 *  This program is distributed in the hope that it will be useful,
 | 
						|
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 *  GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 *  You should have received a copy of the GNU General Public License
 | 
						|
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "qemu.h"
 | 
						|
#include "cpu_loop-common.h"
 | 
						|
 | 
						|
static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
 | 
						|
{
 | 
						|
    return cpu_get_host_ticks();
 | 
						|
}
 | 
						|
 | 
						|
uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
 | 
						|
{
 | 
						|
    return cpu_ppc_get_tb(env);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
 | 
						|
{
 | 
						|
    return cpu_ppc_get_tb(env) >> 32;
 | 
						|
}
 | 
						|
 | 
						|
uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
 | 
						|
{
 | 
						|
    return cpu_ppc_get_tb(env);
 | 
						|
}
 | 
						|
 | 
						|
uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
 | 
						|
{
 | 
						|
    return cpu_ppc_get_tb(env) >> 32;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
 | 
						|
__attribute__ (( alias ("cpu_ppc_load_tbu") ));
 | 
						|
 | 
						|
uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
 | 
						|
{
 | 
						|
    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
 | 
						|
}
 | 
						|
 | 
						|
/* XXX: to be fixed */
 | 
						|
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
 | 
						|
{
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
 | 
						|
{
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
static int do_store_exclusive(CPUPPCState *env)
 | 
						|
{
 | 
						|
    target_ulong addr;
 | 
						|
    target_ulong page_addr;
 | 
						|
    target_ulong val, val2 __attribute__((unused)) = 0;
 | 
						|
    int flags;
 | 
						|
    int segv = 0;
 | 
						|
 | 
						|
    addr = env->reserve_ea;
 | 
						|
    page_addr = addr & TARGET_PAGE_MASK;
 | 
						|
    start_exclusive();
 | 
						|
    mmap_lock();
 | 
						|
    flags = page_get_flags(page_addr);
 | 
						|
    if ((flags & PAGE_READ) == 0) {
 | 
						|
        segv = 1;
 | 
						|
    } else {
 | 
						|
        int reg = env->reserve_info & 0x1f;
 | 
						|
        int size = env->reserve_info >> 5;
 | 
						|
        int stored = 0;
 | 
						|
 | 
						|
        if (addr == env->reserve_addr) {
 | 
						|
            switch (size) {
 | 
						|
            case 1: segv = get_user_u8(val, addr); break;
 | 
						|
            case 2: segv = get_user_u16(val, addr); break;
 | 
						|
            case 4: segv = get_user_u32(val, addr); break;
 | 
						|
#if defined(TARGET_PPC64)
 | 
						|
            case 8: segv = get_user_u64(val, addr); break;
 | 
						|
            case 16: {
 | 
						|
                segv = get_user_u64(val, addr);
 | 
						|
                if (!segv) {
 | 
						|
                    segv = get_user_u64(val2, addr + 8);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
            default: abort();
 | 
						|
            }
 | 
						|
            if (!segv && val == env->reserve_val) {
 | 
						|
                val = env->gpr[reg];
 | 
						|
                switch (size) {
 | 
						|
                case 1: segv = put_user_u8(val, addr); break;
 | 
						|
                case 2: segv = put_user_u16(val, addr); break;
 | 
						|
                case 4: segv = put_user_u32(val, addr); break;
 | 
						|
#if defined(TARGET_PPC64)
 | 
						|
                case 8: segv = put_user_u64(val, addr); break;
 | 
						|
                case 16: {
 | 
						|
                    if (val2 == env->reserve_val2) {
 | 
						|
                        if (msr_le) {
 | 
						|
                            val2 = val;
 | 
						|
                            val = env->gpr[reg+1];
 | 
						|
                        } else {
 | 
						|
                            val2 = env->gpr[reg+1];
 | 
						|
                        }
 | 
						|
                        segv = put_user_u64(val, addr);
 | 
						|
                        if (!segv) {
 | 
						|
                            segv = put_user_u64(val2, addr + 8);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
#endif
 | 
						|
                default: abort();
 | 
						|
                }
 | 
						|
                if (!segv) {
 | 
						|
                    stored = 1;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        env->crf[0] = (stored << 1) | xer_so;
 | 
						|
        env->reserve_addr = (target_ulong)-1;
 | 
						|
    }
 | 
						|
    if (!segv) {
 | 
						|
        env->nip += 4;
 | 
						|
    }
 | 
						|
    mmap_unlock();
 | 
						|
    end_exclusive();
 | 
						|
    return segv;
 | 
						|
}
 | 
						|
 | 
						|
void cpu_loop(CPUPPCState *env)
 | 
						|
{
 | 
						|
    CPUState *cs = CPU(ppc_env_get_cpu(env));
 | 
						|
    target_siginfo_t info;
 | 
						|
    int trapnr;
 | 
						|
    target_ulong ret;
 | 
						|
 | 
						|
    for(;;) {
 | 
						|
        cpu_exec_start(cs);
 | 
						|
        trapnr = cpu_exec(cs);
 | 
						|
        cpu_exec_end(cs);
 | 
						|
        process_queued_cpu_work(cs);
 | 
						|
 | 
						|
        switch(trapnr) {
 | 
						|
        case POWERPC_EXCP_NONE:
 | 
						|
            /* Just go on */
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_CRITICAL: /* Critical input                        */
 | 
						|
            cpu_abort(cs, "Critical interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
 | 
						|
            cpu_abort(cs, "Machine check exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DSI:      /* Data storage exception                */
 | 
						|
            /* XXX: check this. Seems bugged */
 | 
						|
            switch (env->error_code & 0xFF000000) {
 | 
						|
            case 0x40000000:
 | 
						|
            case 0x42000000:
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_MAPERR;
 | 
						|
                break;
 | 
						|
            case 0x04000000:
 | 
						|
                info.si_signo = TARGET_SIGILL;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_ILL_ILLADR;
 | 
						|
                break;
 | 
						|
            case 0x08000000:
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_ACCERR;
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                /* Let's send a regular segfault... */
 | 
						|
                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
 | 
						|
                          env->error_code);
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_MAPERR;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            info._sifields._sigfault._addr = env->spr[SPR_DAR];
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
 | 
						|
            /* XXX: check this */
 | 
						|
            switch (env->error_code & 0xFF000000) {
 | 
						|
            case 0x40000000:
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
            info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_MAPERR;
 | 
						|
                break;
 | 
						|
            case 0x10000000:
 | 
						|
            case 0x08000000:
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_ACCERR;
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                /* Let's send a regular segfault... */
 | 
						|
                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
 | 
						|
                          env->error_code);
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_MAPERR;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            info._sifields._sigfault._addr = env->nip - 4;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_EXTERNAL: /* External input                        */
 | 
						|
            cpu_abort(cs, "External interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
 | 
						|
            /* XXX: check this */
 | 
						|
            info.si_signo = TARGET_SIGBUS;
 | 
						|
            info.si_errno = 0;
 | 
						|
            info.si_code = TARGET_BUS_ADRALN;
 | 
						|
            info._sifields._sigfault._addr = env->nip;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
 | 
						|
        case POWERPC_EXCP_HV_EMU:   /* HV emulation                          */
 | 
						|
            /* XXX: check this */
 | 
						|
            switch (env->error_code & ~0xF) {
 | 
						|
            case POWERPC_EXCP_FP:
 | 
						|
                info.si_signo = TARGET_SIGFPE;
 | 
						|
                info.si_errno = 0;
 | 
						|
                switch (env->error_code & 0xF) {
 | 
						|
                case POWERPC_EXCP_FP_OX:
 | 
						|
                    info.si_code = TARGET_FPE_FLTOVF;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_FP_UX:
 | 
						|
                    info.si_code = TARGET_FPE_FLTUND;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_FP_ZX:
 | 
						|
                case POWERPC_EXCP_FP_VXZDZ:
 | 
						|
                    info.si_code = TARGET_FPE_FLTDIV;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_FP_XX:
 | 
						|
                    info.si_code = TARGET_FPE_FLTRES;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_FP_VXSOFT:
 | 
						|
                    info.si_code = TARGET_FPE_FLTINV;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_FP_VXSNAN:
 | 
						|
                case POWERPC_EXCP_FP_VXISI:
 | 
						|
                case POWERPC_EXCP_FP_VXIDI:
 | 
						|
                case POWERPC_EXCP_FP_VXIMZ:
 | 
						|
                case POWERPC_EXCP_FP_VXVC:
 | 
						|
                case POWERPC_EXCP_FP_VXSQRT:
 | 
						|
                case POWERPC_EXCP_FP_VXCVI:
 | 
						|
                    info.si_code = TARGET_FPE_FLTSUB;
 | 
						|
                    break;
 | 
						|
                default:
 | 
						|
                    EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
 | 
						|
                              env->error_code);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case POWERPC_EXCP_INVAL:
 | 
						|
                info.si_signo = TARGET_SIGILL;
 | 
						|
                info.si_errno = 0;
 | 
						|
                switch (env->error_code & 0xF) {
 | 
						|
                case POWERPC_EXCP_INVAL_INVAL:
 | 
						|
                    info.si_code = TARGET_ILL_ILLOPC;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_INVAL_LSWX:
 | 
						|
                    info.si_code = TARGET_ILL_ILLOPN;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_INVAL_SPR:
 | 
						|
                    info.si_code = TARGET_ILL_PRVREG;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_INVAL_FP:
 | 
						|
                    info.si_code = TARGET_ILL_COPROC;
 | 
						|
                    break;
 | 
						|
                default:
 | 
						|
                    EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
 | 
						|
                              env->error_code & 0xF);
 | 
						|
                    info.si_code = TARGET_ILL_ILLADR;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case POWERPC_EXCP_PRIV:
 | 
						|
                info.si_signo = TARGET_SIGILL;
 | 
						|
                info.si_errno = 0;
 | 
						|
                switch (env->error_code & 0xF) {
 | 
						|
                case POWERPC_EXCP_PRIV_OPC:
 | 
						|
                    info.si_code = TARGET_ILL_PRVOPC;
 | 
						|
                    break;
 | 
						|
                case POWERPC_EXCP_PRIV_REG:
 | 
						|
                    info.si_code = TARGET_ILL_PRVREG;
 | 
						|
                    break;
 | 
						|
                default:
 | 
						|
                    EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
 | 
						|
                              env->error_code & 0xF);
 | 
						|
                    info.si_code = TARGET_ILL_PRVOPC;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case POWERPC_EXCP_TRAP:
 | 
						|
                cpu_abort(cs, "Tried to call a TRAP\n");
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                /* Should not happen ! */
 | 
						|
                cpu_abort(cs, "Unknown program exception (%02x)\n",
 | 
						|
                          env->error_code);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            info._sifields._sigfault._addr = env->nip;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
 | 
						|
            info.si_signo = TARGET_SIGILL;
 | 
						|
            info.si_errno = 0;
 | 
						|
            info.si_code = TARGET_ILL_COPROC;
 | 
						|
            info._sifields._sigfault._addr = env->nip;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
 | 
						|
            cpu_abort(cs, "Syscall exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
 | 
						|
            info.si_signo = TARGET_SIGILL;
 | 
						|
            info.si_errno = 0;
 | 
						|
            info.si_code = TARGET_ILL_COPROC;
 | 
						|
            info._sifields._sigfault._addr = env->nip;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
 | 
						|
            cpu_abort(cs, "Decrementer interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
 | 
						|
            cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
 | 
						|
            cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
 | 
						|
            cpu_abort(cs, "Data TLB exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
 | 
						|
            cpu_abort(cs, "Instruction TLB exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
 | 
						|
            info.si_signo = TARGET_SIGILL;
 | 
						|
            info.si_errno = 0;
 | 
						|
            info.si_code = TARGET_ILL_COPROC;
 | 
						|
            info._sifields._sigfault._addr = env->nip;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
 | 
						|
            cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
 | 
						|
            cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
 | 
						|
            cpu_abort(cs, "Performance monitor exception not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
 | 
						|
            cpu_abort(cs, "Doorbell interrupt while in user mode. "
 | 
						|
                       "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
 | 
						|
            cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_RESET:    /* System reset exception                */
 | 
						|
            cpu_abort(cs, "Reset interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DSEG:     /* Data segment exception                */
 | 
						|
            cpu_abort(cs, "Data segment exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
 | 
						|
            cpu_abort(cs, "Instruction segment exception "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        /* PowerPC 64 with hypervisor mode support */
 | 
						|
        case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
 | 
						|
            cpu_abort(cs, "Hypervisor decrementer interrupt "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_TRACE:    /* Trace exception                       */
 | 
						|
            /* Nothing to do:
 | 
						|
             * we use this exception to emulate step-by-step execution mode.
 | 
						|
             */
 | 
						|
            break;
 | 
						|
        /* PowerPC 64 with hypervisor mode support */
 | 
						|
        case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
 | 
						|
            cpu_abort(cs, "Hypervisor data storage exception "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
 | 
						|
            cpu_abort(cs, "Hypervisor instruction storage exception "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
 | 
						|
            cpu_abort(cs, "Hypervisor data segment exception "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
 | 
						|
            cpu_abort(cs, "Hypervisor instruction segment exception "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
 | 
						|
            info.si_signo = TARGET_SIGILL;
 | 
						|
            info.si_errno = 0;
 | 
						|
            info.si_code = TARGET_ILL_COPROC;
 | 
						|
            info._sifields._sigfault._addr = env->nip;
 | 
						|
            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
 | 
						|
            cpu_abort(cs, "Programmable interval timer interrupt "
 | 
						|
                      "while in user mode. Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_IO:       /* IO error exception                    */
 | 
						|
            cpu_abort(cs, "IO error exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
 | 
						|
            cpu_abort(cs, "Run mode exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
 | 
						|
            cpu_abort(cs, "Emulation trap exception not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
 | 
						|
            cpu_abort(cs, "Instruction fetch TLB exception "
 | 
						|
                      "while in user-mode. Aborting");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
 | 
						|
            cpu_abort(cs, "Data load TLB exception while in user-mode. "
 | 
						|
                      "Aborting");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
 | 
						|
            cpu_abort(cs, "Data store TLB exception while in user-mode. "
 | 
						|
                      "Aborting");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
 | 
						|
            cpu_abort(cs, "Floating-point assist exception not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
 | 
						|
            cpu_abort(cs, "Instruction address breakpoint exception "
 | 
						|
                      "not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_SMI:      /* System management interrupt           */
 | 
						|
            cpu_abort(cs, "System management interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
 | 
						|
            cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
 | 
						|
            cpu_abort(cs, "Performance monitor exception not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
 | 
						|
            cpu_abort(cs, "Vector assist exception not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
 | 
						|
            cpu_abort(cs, "Soft patch exception not handled\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
 | 
						|
            cpu_abort(cs, "Maintenance exception while in user mode. "
 | 
						|
                      "Aborting\n");
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_STOP:     /* stop translation                      */
 | 
						|
            /* We did invalidate the instruction cache. Go on */
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
 | 
						|
            /* We just stopped because of a branch. Go on */
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_SYSCALL_USER:
 | 
						|
            /* system call in user-mode emulation */
 | 
						|
            /* WARNING:
 | 
						|
             * PPC ABI uses overflow flag in cr0 to signal an error
 | 
						|
             * in syscalls.
 | 
						|
             */
 | 
						|
            env->crf[0] &= ~0x1;
 | 
						|
            env->nip += 4;
 | 
						|
            ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
 | 
						|
                             env->gpr[5], env->gpr[6], env->gpr[7],
 | 
						|
                             env->gpr[8], 0, 0);
 | 
						|
            if (ret == -TARGET_ERESTARTSYS) {
 | 
						|
                env->nip -= 4;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
 | 
						|
                /* Returning from a successful sigreturn syscall.
 | 
						|
                   Avoid corrupting register state.  */
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            if (ret > (target_ulong)(-515)) {
 | 
						|
                env->crf[0] |= 0x1;
 | 
						|
                ret = -ret;
 | 
						|
            }
 | 
						|
            env->gpr[3] = ret;
 | 
						|
            break;
 | 
						|
        case POWERPC_EXCP_STCX:
 | 
						|
            if (do_store_exclusive(env)) {
 | 
						|
                info.si_signo = TARGET_SIGSEGV;
 | 
						|
                info.si_errno = 0;
 | 
						|
                info.si_code = TARGET_SEGV_MAPERR;
 | 
						|
                info._sifields._sigfault._addr = env->nip;
 | 
						|
                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case EXCP_DEBUG:
 | 
						|
            {
 | 
						|
                int sig;
 | 
						|
 | 
						|
                sig = gdb_handlesig(cs, TARGET_SIGTRAP);
 | 
						|
                if (sig) {
 | 
						|
                    info.si_signo = sig;
 | 
						|
                    info.si_errno = 0;
 | 
						|
                    info.si_code = TARGET_TRAP_BRKPT;
 | 
						|
                    queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
						|
                  }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case EXCP_INTERRUPT:
 | 
						|
            /* just indicate that signals should be handled asap */
 | 
						|
            break;
 | 
						|
        case EXCP_ATOMIC:
 | 
						|
            cpu_exec_step_atomic(cs);
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        process_pending_signals(env);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
#if defined(TARGET_PPC64)
 | 
						|
    int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
 | 
						|
#if defined(TARGET_ABI32)
 | 
						|
    env->msr &= ~((target_ulong)1 << flag);
 | 
						|
#else
 | 
						|
    env->msr |= (target_ulong)1 << flag;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
    env->nip = regs->nip;
 | 
						|
    for(i = 0; i < 32; i++) {
 | 
						|
        env->gpr[i] = regs->gpr[i];
 | 
						|
    }
 | 
						|
}
 |