linux-user/ppc: Use force_sig_fault

Use the new function instead of setting up a target_siginfo_t
and calling queue_signal.  Fill in the missing PC for SIGTRAP.
The fault address for POWERPC_EXCP_ISI is nip exactly, not nip - 4.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220107213243.212806-20-richard.henderson@linaro.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Richard Henderson 2022-01-07 13:32:38 -08:00 committed by Laurent Vivier
parent b600705669
commit d30e60e7b4
1 changed files with 28 additions and 108 deletions

View File

@ -76,8 +76,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
void cpu_loop(CPUPPCState *env) void cpu_loop(CPUPPCState *env)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
target_siginfo_t info; int trapnr, si_signo, si_code;
int trapnr;
target_ulong ret; target_ulong ret;
for(;;) { for(;;) {
@ -102,61 +101,10 @@ void cpu_loop(CPUPPCState *env)
"Aborting\n"); "Aborting\n");
break; break;
case POWERPC_EXCP_DSI: /* Data storage exception */ 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 */ case POWERPC_EXCP_ISI: /* Instruction storage exception */
/* XXX: check this */ /* FIXME: handle maperr in ppc_cpu_record_sigsegv. */
switch (env->error_code & 0xFF000000) { force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
case 0x40000000: env->spr[SPR_DAR]);
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; break;
case POWERPC_EXCP_EXTERNAL: /* External input */ case POWERPC_EXCP_EXTERNAL: /* External input */
cpu_abort(cs, "External interrupt while in user mode. " cpu_abort(cs, "External interrupt while in user mode. "
@ -167,24 +115,23 @@ void cpu_loop(CPUPPCState *env)
/* XXX: check this */ /* XXX: check this */
switch (env->error_code & ~0xF) { switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP: case POWERPC_EXCP_FP:
info.si_signo = TARGET_SIGFPE; si_signo = TARGET_SIGFPE;
info.si_errno = 0;
switch (env->error_code & 0xF) { switch (env->error_code & 0xF) {
case POWERPC_EXCP_FP_OX: case POWERPC_EXCP_FP_OX:
info.si_code = TARGET_FPE_FLTOVF; si_code = TARGET_FPE_FLTOVF;
break; break;
case POWERPC_EXCP_FP_UX: case POWERPC_EXCP_FP_UX:
info.si_code = TARGET_FPE_FLTUND; si_code = TARGET_FPE_FLTUND;
break; break;
case POWERPC_EXCP_FP_ZX: case POWERPC_EXCP_FP_ZX:
case POWERPC_EXCP_FP_VXZDZ: case POWERPC_EXCP_FP_VXZDZ:
info.si_code = TARGET_FPE_FLTDIV; si_code = TARGET_FPE_FLTDIV;
break; break;
case POWERPC_EXCP_FP_XX: case POWERPC_EXCP_FP_XX:
info.si_code = TARGET_FPE_FLTRES; si_code = TARGET_FPE_FLTRES;
break; break;
case POWERPC_EXCP_FP_VXSOFT: case POWERPC_EXCP_FP_VXSOFT:
info.si_code = TARGET_FPE_FLTINV; si_code = TARGET_FPE_FLTINV;
break; break;
case POWERPC_EXCP_FP_VXSNAN: case POWERPC_EXCP_FP_VXSNAN:
case POWERPC_EXCP_FP_VXISI: case POWERPC_EXCP_FP_VXISI:
@ -193,51 +140,50 @@ void cpu_loop(CPUPPCState *env)
case POWERPC_EXCP_FP_VXVC: case POWERPC_EXCP_FP_VXVC:
case POWERPC_EXCP_FP_VXSQRT: case POWERPC_EXCP_FP_VXSQRT:
case POWERPC_EXCP_FP_VXCVI: case POWERPC_EXCP_FP_VXCVI:
info.si_code = TARGET_FPE_FLTSUB; si_code = TARGET_FPE_FLTSUB;
break; break;
default: default:
EXCP_DUMP(env, "Unknown floating point exception (%02x)\n", EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
env->error_code); env->error_code);
si_code = 0;
break; break;
} }
break; break;
case POWERPC_EXCP_INVAL: case POWERPC_EXCP_INVAL:
info.si_signo = TARGET_SIGILL; si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) { switch (env->error_code & 0xF) {
case POWERPC_EXCP_INVAL_INVAL: case POWERPC_EXCP_INVAL_INVAL:
info.si_code = TARGET_ILL_ILLOPC; si_code = TARGET_ILL_ILLOPC;
break; break;
case POWERPC_EXCP_INVAL_LSWX: case POWERPC_EXCP_INVAL_LSWX:
info.si_code = TARGET_ILL_ILLOPN; si_code = TARGET_ILL_ILLOPN;
break; break;
case POWERPC_EXCP_INVAL_SPR: case POWERPC_EXCP_INVAL_SPR:
info.si_code = TARGET_ILL_PRVREG; si_code = TARGET_ILL_PRVREG;
break; break;
case POWERPC_EXCP_INVAL_FP: case POWERPC_EXCP_INVAL_FP:
info.si_code = TARGET_ILL_COPROC; si_code = TARGET_ILL_COPROC;
break; break;
default: default:
EXCP_DUMP(env, "Unknown invalid operation (%02x)\n", EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
env->error_code & 0xF); env->error_code & 0xF);
info.si_code = TARGET_ILL_ILLADR; si_code = TARGET_ILL_ILLADR;
break; break;
} }
break; break;
case POWERPC_EXCP_PRIV: case POWERPC_EXCP_PRIV:
info.si_signo = TARGET_SIGILL; si_signo = TARGET_SIGILL;
info.si_errno = 0;
switch (env->error_code & 0xF) { switch (env->error_code & 0xF) {
case POWERPC_EXCP_PRIV_OPC: case POWERPC_EXCP_PRIV_OPC:
info.si_code = TARGET_ILL_PRVOPC; si_code = TARGET_ILL_PRVOPC;
break; break;
case POWERPC_EXCP_PRIV_REG: case POWERPC_EXCP_PRIV_REG:
info.si_code = TARGET_ILL_PRVREG; si_code = TARGET_ILL_PRVREG;
break; break;
default: default:
EXCP_DUMP(env, "Unknown privilege violation (%02x)\n", EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
env->error_code & 0xF); env->error_code & 0xF);
info.si_code = TARGET_ILL_PRVOPC; si_code = TARGET_ILL_PRVOPC;
break; break;
} }
break; break;
@ -250,28 +196,19 @@ void cpu_loop(CPUPPCState *env)
env->error_code); env->error_code);
break; break;
} }
info._sifields._sigfault._addr = env->nip; force_sig_fault(si_signo, si_code, env->nip);
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break; break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
info.si_signo = TARGET_SIGILL; case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
info.si_errno = 0; case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
info.si_code = TARGET_ILL_COPROC; case POWERPC_EXCP_VPU: /* Vector unavailable exception */
info._sifields._sigfault._addr = env->nip; force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->nip);
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break; break;
case POWERPC_EXCP_SYSCALL: /* System call exception */ case POWERPC_EXCP_SYSCALL: /* System call exception */
case POWERPC_EXCP_SYSCALL_VECTORED: case POWERPC_EXCP_SYSCALL_VECTORED:
cpu_abort(cs, "Syscall exception while in user mode. " cpu_abort(cs, "Syscall exception while in user mode. "
"Aborting\n"); "Aborting\n");
break; 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 */ case POWERPC_EXCP_DECR: /* Decrementer exception */
cpu_abort(cs, "Decrementer interrupt while in user mode. " cpu_abort(cs, "Decrementer interrupt while in user mode. "
"Aborting\n"); "Aborting\n");
@ -292,13 +229,6 @@ void cpu_loop(CPUPPCState *env)
cpu_abort(cs, "Instruction TLB exception while in user mode. " cpu_abort(cs, "Instruction TLB exception while in user mode. "
"Aborting\n"); "Aborting\n");
break; 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 */ case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
cpu_abort(cs, "Embedded floating-point data IRQ not handled\n"); cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
break; break;
@ -355,13 +285,6 @@ void cpu_loop(CPUPPCState *env)
cpu_abort(cs, "Hypervisor instruction segment exception " cpu_abort(cs, "Hypervisor instruction segment exception "
"while in user mode. Aborting\n"); "while in user mode. Aborting\n");
break; 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 */ case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
cpu_abort(cs, "Programmable interval timer interrupt " cpu_abort(cs, "Programmable interval timer interrupt "
"while in user mode. Aborting\n"); "while in user mode. Aborting\n");
@ -444,10 +367,7 @@ void cpu_loop(CPUPPCState *env)
env->gpr[3] = ret; env->gpr[3] = ret;
break; break;
case EXCP_DEBUG: case EXCP_DEBUG:
info.si_signo = TARGET_SIGTRAP; force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->nip);
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break; break;
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */ /* just indicate that signals should be handled asap */