ppc: Don't update NIP in lswi/lswx/stswi/stswx
Instead, pass GETPC() result to the corresponding helpers. This requires a bit of fiddling to get the PC (hopefully) right in the case where we generate a program check, though the hacks there are temporary, a subsequent patch will clean this all up by always having the nip already set to the right instruction when taking the fault. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> [dwg: Fix trivial checkpatch warning] Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
1b7d17cae4
commit
e41029b378
@ -285,6 +285,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
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;
|
||||
@ -306,6 +310,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
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;
|
||||
|
@ -77,23 +77,30 @@ void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
|
||||
}
|
||||
}
|
||||
|
||||
void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
|
||||
static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
|
||||
uint32_t reg, uintptr_t raddr)
|
||||
{
|
||||
int sh;
|
||||
|
||||
for (; nb > 3; nb -= 4) {
|
||||
env->gpr[reg] = cpu_ldl_data(env, addr);
|
||||
env->gpr[reg] = cpu_ldl_data_ra(env, addr, raddr);
|
||||
reg = (reg + 1) % 32;
|
||||
addr = addr_add(env, addr, 4);
|
||||
}
|
||||
if (unlikely(nb > 0)) {
|
||||
env->gpr[reg] = 0;
|
||||
for (sh = 24; nb > 0; nb--, sh -= 8) {
|
||||
env->gpr[reg] |= cpu_ldub_data(env, addr) << sh;
|
||||
env->gpr[reg] |= cpu_ldub_data_ra(env, addr, raddr) << sh;
|
||||
addr = addr_add(env, addr, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
|
||||
{
|
||||
do_lsw(env, addr, nb, reg, GETPC());
|
||||
}
|
||||
|
||||
/* PPC32 specification says we must generate an exception if
|
||||
* rA is in the range of registers to be loaded.
|
||||
* In an other hand, IBM says this is valid, but rA won't be loaded.
|
||||
@ -106,12 +113,11 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
|
||||
int num_used_regs = (xer_bc + 3) / 4;
|
||||
if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
|
||||
lsw_reg_in_range(reg, num_used_regs, rb))) {
|
||||
env->nip += 4; /* Compensate the "nip - 4" from gen_lswx() */
|
||||
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_INVAL |
|
||||
POWERPC_EXCP_INVAL_LSWX);
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_INVAL |
|
||||
POWERPC_EXCP_INVAL_LSWX, GETPC());
|
||||
} else {
|
||||
helper_lsw(env, addr, xer_bc, reg);
|
||||
do_lsw(env, addr, xer_bc, reg, GETPC());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -122,13 +128,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
|
||||
int sh;
|
||||
|
||||
for (; nb > 3; nb -= 4) {
|
||||
cpu_stl_data(env, addr, env->gpr[reg]);
|
||||
cpu_stl_data_ra(env, addr, env->gpr[reg], GETPC());
|
||||
reg = (reg + 1) % 32;
|
||||
addr = addr_add(env, addr, 4);
|
||||
}
|
||||
if (unlikely(nb > 0)) {
|
||||
for (sh = 24; nb > 0; nb--, sh -= 8) {
|
||||
cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
|
||||
cpu_stb_data_ra(env, addr, (env->gpr[reg] >> sh) & 0xFF, GETPC());
|
||||
addr = addr_add(env, addr, 1);
|
||||
}
|
||||
}
|
||||
|
@ -2916,12 +2916,16 @@ 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;
|
||||
}
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
/* NIP cannot be restored if the memory exception comes from an helper */
|
||||
gen_update_nip(ctx, ctx->nip - 4);
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_register(ctx, t0);
|
||||
t1 = tcg_const_i32(nb);
|
||||
@ -2938,8 +2942,6 @@ static void gen_lswx(DisasContext *ctx)
|
||||
TCGv t0;
|
||||
TCGv_i32 t1, t2, t3;
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
/* NIP cannot be restored if the memory exception comes from an helper */
|
||||
gen_update_nip(ctx, ctx->nip - 4);
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
t1 = tcg_const_i32(rD(ctx->opcode));
|
||||
@ -2959,8 +2961,6 @@ static void gen_stswi(DisasContext *ctx)
|
||||
TCGv_i32 t1, t2;
|
||||
int nb = NB(ctx->opcode);
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
/* NIP cannot be restored if the memory exception comes from an helper */
|
||||
gen_update_nip(ctx, ctx->nip - 4);
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_register(ctx, t0);
|
||||
if (nb == 0)
|
||||
@ -2979,8 +2979,6 @@ static void gen_stswx(DisasContext *ctx)
|
||||
TCGv t0;
|
||||
TCGv_i32 t1, t2;
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
/* NIP cannot be restored if the memory exception comes from an helper */
|
||||
gen_update_nip(ctx, ctx->nip - 4);
|
||||
t0 = tcg_temp_new();
|
||||
gen_addr_reg_index(ctx, t0);
|
||||
t1 = tcg_temp_new_i32();
|
||||
@ -4083,7 +4081,7 @@ static void gen_dcbz(DisasContext *ctx)
|
||||
static void gen_dst(DisasContext *ctx)
|
||||
{
|
||||
if (rA(ctx->opcode) == 0) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
|
||||
} else {
|
||||
/* interpreted as no-op */
|
||||
}
|
||||
@ -4093,7 +4091,7 @@ static void gen_dst(DisasContext *ctx)
|
||||
static void gen_dstst(DisasContext *ctx)
|
||||
{
|
||||
if (rA(ctx->opcode) == 0) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
|
||||
} else {
|
||||
/* interpreted as no-op */
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user