ppc: Make tlb_fill() use new exception helper

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Benjamin Herrenschmidt 2016-07-27 16:56:32 +10:00 committed by David Gibson
parent af6d376ea1
commit bd6fefe71c
4 changed files with 97 additions and 128 deletions

View File

@ -1814,7 +1814,7 @@ void cpu_loop(CPUPPCState *env)
env->error_code);
break;
}
info._sifields._sigfault._addr = env->nip - 4;
info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
@ -1822,7 +1822,7 @@ void cpu_loop(CPUPPCState *env)
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
info._sifields._sigfault._addr = env->nip - 4;
info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
@ -1834,7 +1834,7 @@ void cpu_loop(CPUPPCState *env)
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
info._sifields._sigfault._addr = env->nip - 4;
info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_DECR: /* Decrementer exception */
@ -1862,7 +1862,7 @@ void cpu_loop(CPUPPCState *env)
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
info._sifields._sigfault._addr = env->nip - 4;
info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
@ -1926,7 +1926,7 @@ void cpu_loop(CPUPPCState *env)
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_COPROC;
info._sifields._sigfault._addr = env->nip - 4;
info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
@ -2001,9 +2001,9 @@ void cpu_loop(CPUPPCState *env)
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->nip -= 4;
break;
}
env->nip += 4;
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
/* Returning from a successful sigreturn syscall.
Avoid corrupting register state. */

View File

@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
default:
goto excp_invalid;
}
goto store_next;
break;
case POWERPC_EXCP_MCHECK: /* Machine check exception */
if (msr_me == 0) {
/* Machine check exception is not enabled.
@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
default:
break;
}
goto store_next;
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
"\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
goto store_next;
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
"\n", msr, env->nip);
msr |= env->error_code;
goto store_next;
break;
case POWERPC_EXCP_EXTERNAL: /* External input */
cs = CPU(cpu);
@ -258,13 +258,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
/* IACK the IRQ on delivery */
env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
}
goto store_next;
break;
case POWERPC_EXCP_ALIGN: /* Alignment exception */
/* XXX: this is false */
/* Get rS/rD and rA from faulting opcode */
env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
/* Broken for LE mode */
env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
& 0x03FF0000) >> 16;
goto store_next;
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
switch (env->error_code & ~0xF) {
case POWERPC_EXCP_FP:
@ -280,15 +281,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
* precise in the MSR.
*/
msr |= 0x00100000;
goto store_next;
break;
case POWERPC_EXCP_INVAL:
LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
msr |= 0x00080000;
env->spr[SPR_BOOKE_ESR] = ESR_PIL;
/* Some invalids will have the PC in the right place already */
if (env->error_code & POWERPC_EXCP_INVAL_LSWX) {
goto store_next;
}
break;
case POWERPC_EXCP_PRIV:
msr |= 0x00040000;
@ -304,23 +301,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
env->error_code);
break;
}
goto store_current;
case POWERPC_EXCP_HV_EMU:
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
/* Some invalids will have the PC in the right place already */
if (env->error_code == (POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX)) {
goto store_next;
}
goto store_current;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
goto store_current;
break;
case POWERPC_EXCP_SYSCALL: /* System call exception */
dump_syscall(env);
lev = env->error_code;
/* We need to correct the NIP which in this case is supposed
* to point to the next instruction
*/
env->nip += 4;
/* "PAPR mode" built-in hypercall emulation */
if ((lev == 1) && cpu_ppc_hypercall) {
cpu_ppc_hypercall(cpu);
@ -329,15 +319,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
if (lev == 1) {
new_msr |= (target_ulong)MSR_HVB;
}
goto store_next;
break;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
goto store_current;
case POWERPC_EXCP_DECR: /* Decrementer exception */
goto store_next;
break;
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
/* FIT on 4xx */
LOG_EXCP("FIT exception\n");
goto store_next;
break;
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
LOG_EXCP("WDT exception\n");
switch (excp_model) {
@ -348,11 +338,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
default:
break;
}
goto store_next;
break;
case POWERPC_EXCP_DTLB: /* Data TLB error */
goto store_next;
case POWERPC_EXCP_ITLB: /* Instruction TLB error */
goto store_next;
break;
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
switch (excp_model) {
case POWERPC_EXCP_BOOKE:
@ -367,33 +356,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
}
/* XXX: TODO */
cpu_abort(cs, "Debug exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
goto store_current;
break;
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
/* XXX: TODO */
cpu_abort(cs, "Embedded floating point data exception "
"is not implemented yet !\n");
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
goto store_next;
break;
case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
/* XXX: TODO */
cpu_abort(cs, "Embedded floating point round exception "
"is not implemented yet !\n");
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
goto store_next;
break;
case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
/* XXX: TODO */
cpu_abort(cs,
"Performance counter exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
goto store_next;
break;
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
srr0 = SPR_BOOKE_CSRR0;
srr1 = SPR_BOOKE_CSRR1;
goto store_next;
break;
case POWERPC_EXCP_RESET: /* System reset exception */
if (msr_pow) {
/* indicate that we resumed from power save mode */
@ -404,65 +393,42 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
new_msr |= (target_ulong)MSR_HVB;
ail = 0;
goto store_next;
break;
case POWERPC_EXCP_DSEG: /* Data segment exception */
goto store_next;
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
goto store_next;
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
case POWERPC_EXCP_TRACE: /* Trace exception */
goto store_next;
break;
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
case POWERPC_EXCP_HV_EMU:
srr0 = SPR_HSRR0;
srr1 = SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
break;
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
goto store_current;
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
goto store_current;
case POWERPC_EXCP_FU: /* Facility unavailable exception */
goto store_current;
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
LOG_EXCP("PIT exception\n");
goto store_next;
break;
case POWERPC_EXCP_IO: /* IO error exception */
/* XXX: TODO */
cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_RUNM: /* Run mode exception */
/* XXX: TODO */
cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_EMUL: /* Emulation trap exception */
/* XXX: TODO */
cpu_abort(cs, "602 emulation trap exception "
"is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
switch (excp_model) {
case POWERPC_EXCP_602:
@ -577,71 +543,67 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
cpu_abort(cs, "Invalid data store TLB miss exception\n");
break;
}
goto store_next;
break;
case POWERPC_EXCP_FPA: /* Floating-point assist exception */
/* XXX: TODO */
cpu_abort(cs, "Floating point assist exception "
"is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_DABR: /* Data address breakpoint */
/* XXX: TODO */
cpu_abort(cs, "DABR exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
/* XXX: TODO */
cpu_abort(cs, "IABR exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_SMI: /* System management interrupt */
/* XXX: TODO */
cpu_abort(cs, "SMI exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_THERM: /* Thermal interrupt */
/* XXX: TODO */
cpu_abort(cs, "Thermal management exception "
"is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
/* XXX: TODO */
cpu_abort(cs,
"Performance counter exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_VPUA: /* Vector assist exception */
/* XXX: TODO */
cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_SOFTP: /* Soft patch exception */
/* XXX: TODO */
cpu_abort(cs,
"970 soft-patch exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_MAINT: /* Maintenance exception */
/* XXX: TODO */
cpu_abort(cs,
"970 maintenance exception is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
/* XXX: TODO */
cpu_abort(cs, "Maskable external exception "
"is not implemented yet !\n");
goto store_next;
break;
case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
/* XXX: TODO */
cpu_abort(cs, "Non maskable external exception "
"is not implemented yet !\n");
goto store_next;
break;
default:
excp_invalid:
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
break;
store_current:
/* save current instruction location */
env->spr[srr0] = env->nip - 4;
break;
store_next:
/* save next instruction location */
env->spr[srr0] = env->nip;
break;
}
/* Save PC */
env->spr[srr0] = env->nip;
/* Save MSR */
env->spr[srr1] = msr;

View File

@ -2892,10 +2892,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
}
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
cpu_restore_state(cs, retaddr);
}
helper_raise_exception_err(env, cs->exception_index, env->error_code);
raise_exception_err_ra(env, cs->exception_index, env->error_code,
retaddr);
}
}

View File

@ -276,8 +276,12 @@ void gen_update_current_nip(void *opaque)
static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
{
TCGv_i32 t0, t1;
/* These are all synchronous exceptions, we set the PC back to
* the faulting instruction
*/
if (ctx->exception == POWERPC_EXCP_NONE) {
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
}
t0 = tcg_const_i32(excp);
t1 = tcg_const_i32(error);
@ -290,8 +294,12 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
static void gen_exception(DisasContext *ctx, uint32_t excp)
{
TCGv_i32 t0;
/* These are all synchronous exceptions, we set the PC back to
* the faulting instruction
*/
if (ctx->exception == POWERPC_EXCP_NONE) {
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
}
t0 = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, t0);
@ -299,13 +307,28 @@ static void gen_exception(DisasContext *ctx, uint32_t excp)
ctx->exception = (excp);
}
static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
target_ulong nip)
{
TCGv_i32 t0;
gen_update_nip(ctx, nip);
t0 = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
ctx->exception = (excp);
}
static void gen_debug_exception(DisasContext *ctx)
{
TCGv_i32 t0;
/* These are all synchronous exceptions, we set the PC back to
* the faulting instruction
*/
if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
(ctx->exception != POWERPC_EXCP_SYNC)) {
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
}
t0 = tcg_const_i32(EXCP_DEBUG);
gen_helper_raise_exception(cpu_env, t0);
@ -1643,7 +1666,7 @@ static void gen_pause(DisasContext *ctx)
tcg_temp_free_i32(t0);
/* Stop translation, this gives other CPUs a chance to run */
gen_exception_err(ctx, EXCP_HLT, 1);
gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
}
#endif /* defined(TARGET_PPC64) */
@ -2912,12 +2935,6 @@ static void gen_lswi(DisasContext *ctx)
nb = 32;
nr = (nb + 3) / 4;
if (unlikely(lsw_reg_in_range(start, nr, ra))) {
/* The handler expects the PC to point to *this* instruction,
* so setting ctx->exception here prevents it from being
* improperly updated again by gen_inval_exception
*/
gen_update_nip(ctx, ctx->nip - 4);
ctx->exception = POWERPC_EXCP_HV_EMU;
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
return;
}
@ -3055,16 +3072,12 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
int reg, int size)
{
TCGv t0 = tcg_temp_new();
uint32_t save_exception = ctx->exception;
tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea));
tcg_gen_movi_tl(t0, (size << 5) | reg);
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info));
tcg_temp_free(t0);
gen_update_nip(ctx, ctx->nip-4);
ctx->exception = POWERPC_EXCP_BRANCH;
gen_exception(ctx, POWERPC_EXCP_STCX);
ctx->exception = save_exception;
gen_exception_err(ctx, POWERPC_EXCP_STCX, 0);
}
#else
static void gen_conditional_store(DisasContext *ctx, TCGv EA,
@ -3203,7 +3216,7 @@ static void gen_wait(DisasContext *ctx)
-offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
tcg_temp_free_i32(t0);
/* Stop translation, as the CPU is supposed to sleep from now */
gen_exception_err(ctx, EXCP_HLT, 1);
gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
}
#if defined(TARGET_PPC64)
@ -3306,10 +3319,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
(CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
(ctx->exception == POWERPC_EXCP_BRANCH ||
ctx->exception == POWERPC_EXCP_TRACE)) {
target_ulong tmp = ctx->nip;
ctx->nip = dest;
gen_exception(ctx, POWERPC_EXCP_TRACE);
ctx->nip = tmp;
gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest);
}
if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
gen_debug_exception(ctx);
@ -3578,7 +3588,7 @@ static void gen_tw(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
t0);
tcg_temp_free_i32(t0);
@ -3590,7 +3600,7 @@ static void gen_twi(DisasContext *ctx)
TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
@ -3602,7 +3612,7 @@ static void gen_td(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
t0);
tcg_temp_free_i32(t0);
@ -3614,7 +3624,7 @@ static void gen_tdi(DisasContext *ctx)
TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
gen_update_nip(ctx, ctx->nip - 4);
gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
@ -7054,7 +7064,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
ctx.exception != POWERPC_SYSCALL &&
ctx.exception != POWERPC_EXCP_TRAP &&
ctx.exception != POWERPC_EXCP_BRANCH)) {
gen_exception(ctxp, POWERPC_EXCP_TRACE);
gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
} else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
(cs->singlestep_enabled) ||
singlestep ||