xref: /qemu/linux-user/ppc/cpu_loop.c (revision 75da4997)
1cd71c089SLaurent Vivier /*
2cd71c089SLaurent Vivier  *  qemu user cpu loop
3cd71c089SLaurent Vivier  *
4cd71c089SLaurent Vivier  *  Copyright (c) 2003-2008 Fabrice Bellard
5cd71c089SLaurent Vivier  *
6cd71c089SLaurent Vivier  *  This program is free software; you can redistribute it and/or modify
7cd71c089SLaurent Vivier  *  it under the terms of the GNU General Public License as published by
8cd71c089SLaurent Vivier  *  the Free Software Foundation; either version 2 of the License, or
9cd71c089SLaurent Vivier  *  (at your option) any later version.
10cd71c089SLaurent Vivier  *
11cd71c089SLaurent Vivier  *  This program is distributed in the hope that it will be useful,
12cd71c089SLaurent Vivier  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13cd71c089SLaurent Vivier  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14cd71c089SLaurent Vivier  *  GNU General Public License for more details.
15cd71c089SLaurent Vivier  *
16cd71c089SLaurent Vivier  *  You should have received a copy of the GNU General Public License
17cd71c089SLaurent Vivier  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18cd71c089SLaurent Vivier  */
19cd71c089SLaurent Vivier 
20cd71c089SLaurent Vivier #include "qemu/osdep.h"
21a8d25326SMarkus Armbruster #include "qemu-common.h"
22cd71c089SLaurent Vivier #include "qemu.h"
23cd71c089SLaurent Vivier #include "cpu_loop-common.h"
24cd71c089SLaurent Vivier 
2511400516SLaurent Vivier static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
2611400516SLaurent Vivier {
2711400516SLaurent Vivier     return cpu_get_host_ticks();
2811400516SLaurent Vivier }
2911400516SLaurent Vivier 
3011400516SLaurent Vivier uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
3111400516SLaurent Vivier {
3211400516SLaurent Vivier     return cpu_ppc_get_tb(env);
3311400516SLaurent Vivier }
3411400516SLaurent Vivier 
3511400516SLaurent Vivier uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
3611400516SLaurent Vivier {
3711400516SLaurent Vivier     return cpu_ppc_get_tb(env) >> 32;
3811400516SLaurent Vivier }
3911400516SLaurent Vivier 
4011400516SLaurent Vivier uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
4111400516SLaurent Vivier {
4211400516SLaurent Vivier     return cpu_ppc_get_tb(env);
4311400516SLaurent Vivier }
4411400516SLaurent Vivier 
4511400516SLaurent Vivier uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
4611400516SLaurent Vivier {
4711400516SLaurent Vivier     return cpu_ppc_get_tb(env) >> 32;
4811400516SLaurent Vivier }
4911400516SLaurent Vivier 
505d62725bSSuraj Jitindar Singh uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
515d62725bSSuraj Jitindar Singh {
525d62725bSSuraj Jitindar Singh     return cpu_ppc_get_tb(env);
535d62725bSSuraj Jitindar Singh }
545d62725bSSuraj Jitindar Singh 
5511400516SLaurent Vivier uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
5611400516SLaurent Vivier __attribute__ (( alias ("cpu_ppc_load_tbu") ));
5711400516SLaurent Vivier 
5811400516SLaurent Vivier uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
5911400516SLaurent Vivier {
6011400516SLaurent Vivier     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
6111400516SLaurent Vivier }
6211400516SLaurent Vivier 
6311400516SLaurent Vivier /* XXX: to be fixed */
6411400516SLaurent Vivier int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
6511400516SLaurent Vivier {
6611400516SLaurent Vivier     return -1;
6711400516SLaurent Vivier }
6811400516SLaurent Vivier 
6911400516SLaurent Vivier int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
7011400516SLaurent Vivier {
7111400516SLaurent Vivier     return -1;
7211400516SLaurent Vivier }
7311400516SLaurent Vivier 
7411400516SLaurent Vivier void cpu_loop(CPUPPCState *env)
7511400516SLaurent Vivier {
76db70b311SRichard Henderson     CPUState *cs = env_cpu(env);
7711400516SLaurent Vivier     target_siginfo_t info;
78b10089a1SPeter Maydell     int trapnr;
7911400516SLaurent Vivier     target_ulong ret;
8011400516SLaurent Vivier 
8111400516SLaurent Vivier     for(;;) {
8214db1899SRichard Henderson         bool arch_interrupt;
8314db1899SRichard Henderson 
8411400516SLaurent Vivier         cpu_exec_start(cs);
8511400516SLaurent Vivier         trapnr = cpu_exec(cs);
8611400516SLaurent Vivier         cpu_exec_end(cs);
8711400516SLaurent Vivier         process_queued_cpu_work(cs);
8811400516SLaurent Vivier 
8914db1899SRichard Henderson         arch_interrupt = true;
9011400516SLaurent Vivier         switch (trapnr) {
9111400516SLaurent Vivier         case POWERPC_EXCP_NONE:
9211400516SLaurent Vivier             /* Just go on */
9311400516SLaurent Vivier             break;
9411400516SLaurent Vivier         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
9511400516SLaurent Vivier             cpu_abort(cs, "Critical interrupt while in user mode. "
9611400516SLaurent Vivier                       "Aborting\n");
9711400516SLaurent Vivier             break;
9811400516SLaurent Vivier         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
9911400516SLaurent Vivier             cpu_abort(cs, "Machine check exception while in user mode. "
10011400516SLaurent Vivier                       "Aborting\n");
10111400516SLaurent Vivier             break;
10211400516SLaurent Vivier         case POWERPC_EXCP_DSI:      /* Data storage exception                */
10311400516SLaurent Vivier             /* XXX: check this. Seems bugged */
10411400516SLaurent Vivier             switch (env->error_code & 0xFF000000) {
10511400516SLaurent Vivier             case 0x40000000:
10611400516SLaurent Vivier             case 0x42000000:
10711400516SLaurent Vivier                 info.si_signo = TARGET_SIGSEGV;
10811400516SLaurent Vivier                 info.si_errno = 0;
10911400516SLaurent Vivier                 info.si_code = TARGET_SEGV_MAPERR;
11011400516SLaurent Vivier                 break;
11111400516SLaurent Vivier             case 0x04000000:
11211400516SLaurent Vivier                 info.si_signo = TARGET_SIGILL;
11311400516SLaurent Vivier                 info.si_errno = 0;
11411400516SLaurent Vivier                 info.si_code = TARGET_ILL_ILLADR;
11511400516SLaurent Vivier                 break;
11611400516SLaurent Vivier             case 0x08000000:
11711400516SLaurent Vivier                 info.si_signo = TARGET_SIGSEGV;
11811400516SLaurent Vivier                 info.si_errno = 0;
11911400516SLaurent Vivier                 info.si_code = TARGET_SEGV_ACCERR;
12011400516SLaurent Vivier                 break;
12111400516SLaurent Vivier             default:
12211400516SLaurent Vivier                 /* Let's send a regular segfault... */
12311400516SLaurent Vivier                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
12411400516SLaurent Vivier                           env->error_code);
12511400516SLaurent Vivier                 info.si_signo = TARGET_SIGSEGV;
12611400516SLaurent Vivier                 info.si_errno = 0;
12711400516SLaurent Vivier                 info.si_code = TARGET_SEGV_MAPERR;
12811400516SLaurent Vivier                 break;
12911400516SLaurent Vivier             }
13011400516SLaurent Vivier             info._sifields._sigfault._addr = env->spr[SPR_DAR];
13111400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
13211400516SLaurent Vivier             break;
13311400516SLaurent Vivier         case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
13411400516SLaurent Vivier             /* XXX: check this */
13511400516SLaurent Vivier             switch (env->error_code & 0xFF000000) {
13611400516SLaurent Vivier             case 0x40000000:
13711400516SLaurent Vivier                 info.si_signo = TARGET_SIGSEGV;
13811400516SLaurent Vivier             info.si_errno = 0;
13911400516SLaurent Vivier                 info.si_code = TARGET_SEGV_MAPERR;
14011400516SLaurent Vivier                 break;
14111400516SLaurent Vivier             case 0x10000000:
14211400516SLaurent Vivier             case 0x08000000:
14311400516SLaurent Vivier                 info.si_signo = TARGET_SIGSEGV;
14411400516SLaurent Vivier                 info.si_errno = 0;
14511400516SLaurent Vivier                 info.si_code = TARGET_SEGV_ACCERR;
14611400516SLaurent Vivier                 break;
14711400516SLaurent Vivier             default:
14811400516SLaurent Vivier                 /* Let's send a regular segfault... */
14911400516SLaurent Vivier                 EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
15011400516SLaurent Vivier                           env->error_code);
15111400516SLaurent Vivier                 info.si_signo = TARGET_SIGSEGV;
15211400516SLaurent Vivier                 info.si_errno = 0;
15311400516SLaurent Vivier                 info.si_code = TARGET_SEGV_MAPERR;
15411400516SLaurent Vivier                 break;
15511400516SLaurent Vivier             }
15611400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip - 4;
15711400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
15811400516SLaurent Vivier             break;
15911400516SLaurent Vivier         case POWERPC_EXCP_EXTERNAL: /* External input                        */
16011400516SLaurent Vivier             cpu_abort(cs, "External interrupt while in user mode. "
16111400516SLaurent Vivier                       "Aborting\n");
16211400516SLaurent Vivier             break;
16311400516SLaurent Vivier         case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
16411400516SLaurent Vivier             /* XXX: check this */
16511400516SLaurent Vivier             info.si_signo = TARGET_SIGBUS;
16611400516SLaurent Vivier             info.si_errno = 0;
16711400516SLaurent Vivier             info.si_code = TARGET_BUS_ADRALN;
16811400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip;
16911400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
17011400516SLaurent Vivier             break;
17111400516SLaurent Vivier         case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
17211400516SLaurent Vivier         case POWERPC_EXCP_HV_EMU:   /* HV emulation                          */
17311400516SLaurent Vivier             /* XXX: check this */
17411400516SLaurent Vivier             switch (env->error_code & ~0xF) {
17511400516SLaurent Vivier             case POWERPC_EXCP_FP:
17611400516SLaurent Vivier                 info.si_signo = TARGET_SIGFPE;
17711400516SLaurent Vivier                 info.si_errno = 0;
17811400516SLaurent Vivier                 switch (env->error_code & 0xF) {
17911400516SLaurent Vivier                 case POWERPC_EXCP_FP_OX:
18011400516SLaurent Vivier                     info.si_code = TARGET_FPE_FLTOVF;
18111400516SLaurent Vivier                     break;
18211400516SLaurent Vivier                 case POWERPC_EXCP_FP_UX:
18311400516SLaurent Vivier                     info.si_code = TARGET_FPE_FLTUND;
18411400516SLaurent Vivier                     break;
18511400516SLaurent Vivier                 case POWERPC_EXCP_FP_ZX:
18611400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXZDZ:
18711400516SLaurent Vivier                     info.si_code = TARGET_FPE_FLTDIV;
18811400516SLaurent Vivier                     break;
18911400516SLaurent Vivier                 case POWERPC_EXCP_FP_XX:
19011400516SLaurent Vivier                     info.si_code = TARGET_FPE_FLTRES;
19111400516SLaurent Vivier                     break;
19211400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXSOFT:
19311400516SLaurent Vivier                     info.si_code = TARGET_FPE_FLTINV;
19411400516SLaurent Vivier                     break;
19511400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXSNAN:
19611400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXISI:
19711400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXIDI:
19811400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXIMZ:
19911400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXVC:
20011400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXSQRT:
20111400516SLaurent Vivier                 case POWERPC_EXCP_FP_VXCVI:
20211400516SLaurent Vivier                     info.si_code = TARGET_FPE_FLTSUB;
20311400516SLaurent Vivier                     break;
20411400516SLaurent Vivier                 default:
20511400516SLaurent Vivier                     EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
20611400516SLaurent Vivier                               env->error_code);
20711400516SLaurent Vivier                     break;
20811400516SLaurent Vivier                 }
20911400516SLaurent Vivier                 break;
21011400516SLaurent Vivier             case POWERPC_EXCP_INVAL:
21111400516SLaurent Vivier                 info.si_signo = TARGET_SIGILL;
21211400516SLaurent Vivier                 info.si_errno = 0;
21311400516SLaurent Vivier                 switch (env->error_code & 0xF) {
21411400516SLaurent Vivier                 case POWERPC_EXCP_INVAL_INVAL:
21511400516SLaurent Vivier                     info.si_code = TARGET_ILL_ILLOPC;
21611400516SLaurent Vivier                     break;
21711400516SLaurent Vivier                 case POWERPC_EXCP_INVAL_LSWX:
21811400516SLaurent Vivier                     info.si_code = TARGET_ILL_ILLOPN;
21911400516SLaurent Vivier                     break;
22011400516SLaurent Vivier                 case POWERPC_EXCP_INVAL_SPR:
22111400516SLaurent Vivier                     info.si_code = TARGET_ILL_PRVREG;
22211400516SLaurent Vivier                     break;
22311400516SLaurent Vivier                 case POWERPC_EXCP_INVAL_FP:
22411400516SLaurent Vivier                     info.si_code = TARGET_ILL_COPROC;
22511400516SLaurent Vivier                     break;
22611400516SLaurent Vivier                 default:
22711400516SLaurent Vivier                     EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
22811400516SLaurent Vivier                               env->error_code & 0xF);
22911400516SLaurent Vivier                     info.si_code = TARGET_ILL_ILLADR;
23011400516SLaurent Vivier                     break;
23111400516SLaurent Vivier                 }
23211400516SLaurent Vivier                 break;
23311400516SLaurent Vivier             case POWERPC_EXCP_PRIV:
23411400516SLaurent Vivier                 info.si_signo = TARGET_SIGILL;
23511400516SLaurent Vivier                 info.si_errno = 0;
23611400516SLaurent Vivier                 switch (env->error_code & 0xF) {
23711400516SLaurent Vivier                 case POWERPC_EXCP_PRIV_OPC:
23811400516SLaurent Vivier                     info.si_code = TARGET_ILL_PRVOPC;
23911400516SLaurent Vivier                     break;
24011400516SLaurent Vivier                 case POWERPC_EXCP_PRIV_REG:
24111400516SLaurent Vivier                     info.si_code = TARGET_ILL_PRVREG;
24211400516SLaurent Vivier                     break;
24311400516SLaurent Vivier                 default:
24411400516SLaurent Vivier                     EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
24511400516SLaurent Vivier                               env->error_code & 0xF);
24611400516SLaurent Vivier                     info.si_code = TARGET_ILL_PRVOPC;
24711400516SLaurent Vivier                     break;
24811400516SLaurent Vivier                 }
24911400516SLaurent Vivier                 break;
25011400516SLaurent Vivier             case POWERPC_EXCP_TRAP:
25111400516SLaurent Vivier                 cpu_abort(cs, "Tried to call a TRAP\n");
25211400516SLaurent Vivier                 break;
25311400516SLaurent Vivier             default:
25411400516SLaurent Vivier                 /* Should not happen ! */
25511400516SLaurent Vivier                 cpu_abort(cs, "Unknown program exception (%02x)\n",
25611400516SLaurent Vivier                           env->error_code);
25711400516SLaurent Vivier                 break;
25811400516SLaurent Vivier             }
25911400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip;
26011400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
26111400516SLaurent Vivier             break;
26211400516SLaurent Vivier         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
26311400516SLaurent Vivier             info.si_signo = TARGET_SIGILL;
26411400516SLaurent Vivier             info.si_errno = 0;
26511400516SLaurent Vivier             info.si_code = TARGET_ILL_COPROC;
26611400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip;
26711400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
26811400516SLaurent Vivier             break;
26911400516SLaurent Vivier         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
2703c89b8d6SNicholas Piggin         case POWERPC_EXCP_SYSCALL_VECTORED:
27111400516SLaurent Vivier             cpu_abort(cs, "Syscall exception while in user mode. "
27211400516SLaurent Vivier                       "Aborting\n");
27311400516SLaurent Vivier             break;
27411400516SLaurent Vivier         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
27511400516SLaurent Vivier             info.si_signo = TARGET_SIGILL;
27611400516SLaurent Vivier             info.si_errno = 0;
27711400516SLaurent Vivier             info.si_code = TARGET_ILL_COPROC;
27811400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip;
27911400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
28011400516SLaurent Vivier             break;
28111400516SLaurent Vivier         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
28211400516SLaurent Vivier             cpu_abort(cs, "Decrementer interrupt while in user mode. "
28311400516SLaurent Vivier                       "Aborting\n");
28411400516SLaurent Vivier             break;
28511400516SLaurent Vivier         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
28611400516SLaurent Vivier             cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
28711400516SLaurent Vivier                       "Aborting\n");
28811400516SLaurent Vivier             break;
28911400516SLaurent Vivier         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
29011400516SLaurent Vivier             cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
29111400516SLaurent Vivier                       "Aborting\n");
29211400516SLaurent Vivier             break;
29311400516SLaurent Vivier         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
29411400516SLaurent Vivier             cpu_abort(cs, "Data TLB exception while in user mode. "
29511400516SLaurent Vivier                       "Aborting\n");
29611400516SLaurent Vivier             break;
29711400516SLaurent Vivier         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
29811400516SLaurent Vivier             cpu_abort(cs, "Instruction TLB exception while in user mode. "
29911400516SLaurent Vivier                       "Aborting\n");
30011400516SLaurent Vivier             break;
30111400516SLaurent Vivier         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
30211400516SLaurent Vivier             info.si_signo = TARGET_SIGILL;
30311400516SLaurent Vivier             info.si_errno = 0;
30411400516SLaurent Vivier             info.si_code = TARGET_ILL_COPROC;
30511400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip;
30611400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
30711400516SLaurent Vivier             break;
30811400516SLaurent Vivier         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
30911400516SLaurent Vivier             cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
31011400516SLaurent Vivier             break;
31111400516SLaurent Vivier         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
31211400516SLaurent Vivier             cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
31311400516SLaurent Vivier             break;
31411400516SLaurent Vivier         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
31511400516SLaurent Vivier             cpu_abort(cs, "Performance monitor exception not handled\n");
31611400516SLaurent Vivier             break;
31711400516SLaurent Vivier         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
31811400516SLaurent Vivier             cpu_abort(cs, "Doorbell interrupt while in user mode. "
31911400516SLaurent Vivier                        "Aborting\n");
32011400516SLaurent Vivier             break;
32111400516SLaurent Vivier         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
32211400516SLaurent Vivier             cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
32311400516SLaurent Vivier                       "Aborting\n");
32411400516SLaurent Vivier             break;
32511400516SLaurent Vivier         case POWERPC_EXCP_RESET:    /* System reset exception                */
32611400516SLaurent Vivier             cpu_abort(cs, "Reset interrupt while in user mode. "
32711400516SLaurent Vivier                       "Aborting\n");
32811400516SLaurent Vivier             break;
32911400516SLaurent Vivier         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
33011400516SLaurent Vivier             cpu_abort(cs, "Data segment exception while in user mode. "
33111400516SLaurent Vivier                       "Aborting\n");
33211400516SLaurent Vivier             break;
33311400516SLaurent Vivier         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
33411400516SLaurent Vivier             cpu_abort(cs, "Instruction segment exception "
33511400516SLaurent Vivier                       "while in user mode. Aborting\n");
33611400516SLaurent Vivier             break;
33711400516SLaurent Vivier         /* PowerPC 64 with hypervisor mode support */
33811400516SLaurent Vivier         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
33911400516SLaurent Vivier             cpu_abort(cs, "Hypervisor decrementer interrupt "
34011400516SLaurent Vivier                       "while in user mode. Aborting\n");
34111400516SLaurent Vivier             break;
34211400516SLaurent Vivier         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
34311400516SLaurent Vivier             /* Nothing to do:
34411400516SLaurent Vivier              * we use this exception to emulate step-by-step execution mode.
34511400516SLaurent Vivier              */
34611400516SLaurent Vivier             break;
34711400516SLaurent Vivier         /* PowerPC 64 with hypervisor mode support */
34811400516SLaurent Vivier         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
34911400516SLaurent Vivier             cpu_abort(cs, "Hypervisor data storage exception "
35011400516SLaurent Vivier                       "while in user mode. Aborting\n");
35111400516SLaurent Vivier             break;
35211400516SLaurent Vivier         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
35311400516SLaurent Vivier             cpu_abort(cs, "Hypervisor instruction storage exception "
35411400516SLaurent Vivier                       "while in user mode. Aborting\n");
35511400516SLaurent Vivier             break;
35611400516SLaurent Vivier         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
35711400516SLaurent Vivier             cpu_abort(cs, "Hypervisor data segment exception "
35811400516SLaurent Vivier                       "while in user mode. Aborting\n");
35911400516SLaurent Vivier             break;
36011400516SLaurent Vivier         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
36111400516SLaurent Vivier             cpu_abort(cs, "Hypervisor instruction segment exception "
36211400516SLaurent Vivier                       "while in user mode. Aborting\n");
36311400516SLaurent Vivier             break;
36411400516SLaurent Vivier         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
36511400516SLaurent Vivier             info.si_signo = TARGET_SIGILL;
36611400516SLaurent Vivier             info.si_errno = 0;
36711400516SLaurent Vivier             info.si_code = TARGET_ILL_COPROC;
36811400516SLaurent Vivier             info._sifields._sigfault._addr = env->nip;
36911400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
37011400516SLaurent Vivier             break;
37111400516SLaurent Vivier         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
37211400516SLaurent Vivier             cpu_abort(cs, "Programmable interval timer interrupt "
37311400516SLaurent Vivier                       "while in user mode. Aborting\n");
37411400516SLaurent Vivier             break;
37511400516SLaurent Vivier         case POWERPC_EXCP_IO:       /* IO error exception                    */
37611400516SLaurent Vivier             cpu_abort(cs, "IO error exception while in user mode. "
37711400516SLaurent Vivier                       "Aborting\n");
37811400516SLaurent Vivier             break;
37911400516SLaurent Vivier         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
38011400516SLaurent Vivier             cpu_abort(cs, "Run mode exception while in user mode. "
38111400516SLaurent Vivier                       "Aborting\n");
38211400516SLaurent Vivier             break;
38311400516SLaurent Vivier         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
38411400516SLaurent Vivier             cpu_abort(cs, "Emulation trap exception not handled\n");
38511400516SLaurent Vivier             break;
38611400516SLaurent Vivier         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
38711400516SLaurent Vivier             cpu_abort(cs, "Instruction fetch TLB exception "
38811400516SLaurent Vivier                       "while in user-mode. Aborting");
38911400516SLaurent Vivier             break;
39011400516SLaurent Vivier         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
39111400516SLaurent Vivier             cpu_abort(cs, "Data load TLB exception while in user-mode. "
39211400516SLaurent Vivier                       "Aborting");
39311400516SLaurent Vivier             break;
39411400516SLaurent Vivier         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
39511400516SLaurent Vivier             cpu_abort(cs, "Data store TLB exception while in user-mode. "
39611400516SLaurent Vivier                       "Aborting");
39711400516SLaurent Vivier             break;
39811400516SLaurent Vivier         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
39911400516SLaurent Vivier             cpu_abort(cs, "Floating-point assist exception not handled\n");
40011400516SLaurent Vivier             break;
40111400516SLaurent Vivier         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
40211400516SLaurent Vivier             cpu_abort(cs, "Instruction address breakpoint exception "
40311400516SLaurent Vivier                       "not handled\n");
40411400516SLaurent Vivier             break;
40511400516SLaurent Vivier         case POWERPC_EXCP_SMI:      /* System management interrupt           */
40611400516SLaurent Vivier             cpu_abort(cs, "System management interrupt while in user mode. "
40711400516SLaurent Vivier                       "Aborting\n");
40811400516SLaurent Vivier             break;
40911400516SLaurent Vivier         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
41011400516SLaurent Vivier             cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
41111400516SLaurent Vivier                       "Aborting\n");
41211400516SLaurent Vivier             break;
41311400516SLaurent Vivier         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
41411400516SLaurent Vivier             cpu_abort(cs, "Performance monitor exception not handled\n");
41511400516SLaurent Vivier             break;
41611400516SLaurent Vivier         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
41711400516SLaurent Vivier             cpu_abort(cs, "Vector assist exception not handled\n");
41811400516SLaurent Vivier             break;
41911400516SLaurent Vivier         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
42011400516SLaurent Vivier             cpu_abort(cs, "Soft patch exception not handled\n");
42111400516SLaurent Vivier             break;
42211400516SLaurent Vivier         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
42311400516SLaurent Vivier             cpu_abort(cs, "Maintenance exception while in user mode. "
42411400516SLaurent Vivier                       "Aborting\n");
42511400516SLaurent Vivier             break;
42611400516SLaurent Vivier         case POWERPC_EXCP_STOP:     /* stop translation                      */
42711400516SLaurent Vivier             /* We did invalidate the instruction cache. Go on */
42811400516SLaurent Vivier             break;
42911400516SLaurent Vivier         case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
43011400516SLaurent Vivier             /* We just stopped because of a branch. Go on */
43111400516SLaurent Vivier             break;
43211400516SLaurent Vivier         case POWERPC_EXCP_SYSCALL_USER:
43311400516SLaurent Vivier             /* system call in user-mode emulation */
43411400516SLaurent Vivier             /* WARNING:
43511400516SLaurent Vivier              * PPC ABI uses overflow flag in cr0 to signal an error
43611400516SLaurent Vivier              * in syscalls.
43711400516SLaurent Vivier              */
43811400516SLaurent Vivier             env->crf[0] &= ~0x1;
43911400516SLaurent Vivier             env->nip += 4;
44011400516SLaurent Vivier             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
44111400516SLaurent Vivier                              env->gpr[5], env->gpr[6], env->gpr[7],
44211400516SLaurent Vivier                              env->gpr[8], 0, 0);
44311400516SLaurent Vivier             if (ret == -TARGET_ERESTARTSYS) {
44411400516SLaurent Vivier                 env->nip -= 4;
44511400516SLaurent Vivier                 break;
44611400516SLaurent Vivier             }
44711400516SLaurent Vivier             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
44811400516SLaurent Vivier                 /* Returning from a successful sigreturn syscall.
44911400516SLaurent Vivier                    Avoid corrupting register state.  */
45011400516SLaurent Vivier                 break;
45111400516SLaurent Vivier             }
45211400516SLaurent Vivier             if (ret > (target_ulong)(-515)) {
45311400516SLaurent Vivier                 env->crf[0] |= 0x1;
45411400516SLaurent Vivier                 ret = -ret;
45511400516SLaurent Vivier             }
45611400516SLaurent Vivier             env->gpr[3] = ret;
45711400516SLaurent Vivier             break;
45811400516SLaurent Vivier         case EXCP_DEBUG:
459b10089a1SPeter Maydell             info.si_signo = TARGET_SIGTRAP;
46011400516SLaurent Vivier             info.si_errno = 0;
46111400516SLaurent Vivier             info.si_code = TARGET_TRAP_BRKPT;
46211400516SLaurent Vivier             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
46311400516SLaurent Vivier             break;
46411400516SLaurent Vivier         case EXCP_INTERRUPT:
46511400516SLaurent Vivier             /* just indicate that signals should be handled asap */
46611400516SLaurent Vivier             break;
46711400516SLaurent Vivier         case EXCP_ATOMIC:
46811400516SLaurent Vivier             cpu_exec_step_atomic(cs);
46914db1899SRichard Henderson             arch_interrupt = false;
47011400516SLaurent Vivier             break;
47111400516SLaurent Vivier         default:
47211400516SLaurent Vivier             cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
47311400516SLaurent Vivier             break;
47411400516SLaurent Vivier         }
47511400516SLaurent Vivier         process_pending_signals(env);
47614db1899SRichard Henderson 
47714db1899SRichard Henderson         /* Most of the traps imply a transition through kernel mode,
47814db1899SRichard Henderson          * which implies an REI instruction has been executed.  Which
47914db1899SRichard Henderson          * means that RX and LOCK_ADDR should be cleared.  But there
48014db1899SRichard Henderson          * are a few exceptions for traps internal to QEMU.
48114db1899SRichard Henderson          */
48214db1899SRichard Henderson         if (arch_interrupt) {
48314db1899SRichard Henderson             env->reserve_addr = -1;
48414db1899SRichard Henderson         }
48511400516SLaurent Vivier     }
48611400516SLaurent Vivier }
48711400516SLaurent Vivier 
488cd71c089SLaurent Vivier void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
489cd71c089SLaurent Vivier {
49011400516SLaurent Vivier     int i;
49111400516SLaurent Vivier 
49211400516SLaurent Vivier #if defined(TARGET_PPC64)
49311400516SLaurent Vivier     int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
49411400516SLaurent Vivier #if defined(TARGET_ABI32)
495*75da4997SRichard Henderson     ppc_store_msr(env, env->msr & ~((target_ulong)1 << flag));
49611400516SLaurent Vivier #else
497*75da4997SRichard Henderson     ppc_store_msr(env, env->msr | (target_ulong)1 << flag);
49811400516SLaurent Vivier #endif
49911400516SLaurent Vivier #endif
500*75da4997SRichard Henderson 
50111400516SLaurent Vivier     env->nip = regs->nip;
50211400516SLaurent Vivier     for(i = 0; i < 32; i++) {
50311400516SLaurent Vivier         env->gpr[i] = regs->gpr[i];
50411400516SLaurent Vivier     }
505cd71c089SLaurent Vivier }
506