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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Benjamin Herrenschmidt
						Benjamin Herrenschmidt