From a42bd6ccdfefbadfc34d381c42d64a78f532df63 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Fri, 30 Mar 2007 10:22:46 +0000 Subject: [PATCH] Fix rfi instruction: do not depend on current execution mode but on the execution mode that will be effective after the return. Add rfci, rfdi and rfmci for BookE PowerPC. Extend mfdcr / mtdcr and implement mfdrcx / mtdcrx. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2544 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-ppc/op.c | 44 +++++++++------- target-ppc/op_helper.c | 112 +++++++++++++++++++++++++++-------------- target-ppc/op_helper.h | 11 ++-- target-ppc/translate.c | 109 ++++++++++++++++++++++++++++++++------- 4 files changed, 196 insertions(+), 80 deletions(-) diff --git a/target-ppc/op.c b/target-ppc/op.c index 8bbbd62d47..b284798dc7 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -1821,23 +1821,11 @@ void OPPROTO op_rfi (void) } #if defined(TARGET_PPC64) -void OPPROTO op_rfi_32 (void) -{ - do_rfi_32(); - RETURN(); -} - void OPPROTO op_rfid (void) { do_rfid(); RETURN(); } - -void OPPROTO op_rfid_32 (void) -{ - do_rfid_32(); - RETURN(); -} #endif #endif @@ -2309,28 +2297,46 @@ void OPPROTO op_405_check_satu (void) } #if !defined(CONFIG_USER_ONLY) -void OPPROTO op_4xx_load_dcr (void) +void OPPROTO op_load_dcr (void) { - do_4xx_load_dcr(PARAM1); + do_load_dcr(); RETURN(); } -void OPPROTO op_4xx_store_dcr (void) +void OPPROTO op_store_dcr (void) { - do_4xx_store_dcr(PARAM1); + do_store_dcr(); RETURN(); } /* Return from critical interrupt : * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1 */ -void OPPROTO op_4xx_rfci (void) +void OPPROTO op_40x_rfci (void) { - do_4xx_rfci(); + do_40x_rfci(); RETURN(); } -void OPPROTO op_4xx_wrte (void) +void OPPROTO op_rfci (void) +{ + do_rfci(); + RETURN(); +} + +void OPPROTO op_rfdi (void) +{ + do_rfdi(); + RETURN(); +} + +void OPPROTO op_rfmci (void) +{ + do_rfmci(); + RETURN(); +} + +void OPPROTO op_wrte (void) { msr_ee = T0 >> 16; RETURN(); diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 55b5ca5653..c21a38aea4 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -881,12 +881,17 @@ void do_fcmpo (void) #if !defined (CONFIG_USER_ONLY) void do_rfi (void) { - env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); #if defined(TARGET_PPC64) - ppc_store_msr_32(env, T0); + if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { + env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } else { + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } #else - do_store_msr(env, T0); + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); #endif #if defined (DEBUG_OP) dump_rfi(); @@ -895,33 +900,15 @@ void do_rfi (void) } #if defined(TARGET_PPC64) -void do_rfi_32 (void) -{ - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); - ppc_store_msr_32(env, T0); -#if defined (DEBUG_OP) - dump_rfi(); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; -} - void do_rfid (void) { - env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); - do_store_msr(env, T0); -#if defined (DEBUG_OP) - dump_rfi(); -#endif - env->interrupt_request |= CPU_INTERRUPT_EXITTB; -} - -void do_rfid_32 (void) -{ - env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); - T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); - do_store_msr(env, T0); + if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) { + env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } else { + env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003); + do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL)); + } #if defined (DEBUG_OP) dump_rfi(); #endif @@ -936,8 +923,9 @@ void do_tw (int flags) ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) || ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) || ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) || - ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) + ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) { do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); + } } #if defined(TARGET_PPC64) @@ -1196,34 +1184,84 @@ void do_405_check_sat (void) } #if !defined(CONFIG_USER_ONLY) -void do_4xx_rfci (void) +void do_40x_rfci (void) { env->nip = env->spr[SPR_40x_SRR2]; - T0 = env->spr[SPR_40x_SRR3] & ~0xFFFF0000; - do_store_msr(env, T0); + do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000); #if defined (DEBUG_OP) dump_rfi(); #endif env->interrupt_request = CPU_INTERRUPT_EXITTB; } -void do_4xx_load_dcr (int dcrn) +void do_rfci (void) +{ +#if defined(TARGET_PPC64) + if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) { + env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0]; + } else +#endif + { + env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0]; + } + do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_rfdi (void) +{ +#if defined(TARGET_PPC64) + if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) { + env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0]; + } else +#endif + { + env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0]; + } + do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_rfmci (void) +{ +#if defined(TARGET_PPC64) + if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) { + env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0]; + } else +#endif + { + env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0]; + } + do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000); +#if defined (DEBUG_OP) + dump_rfi(); +#endif + env->interrupt_request = CPU_INTERRUPT_EXITTB; +} + +void do_load_dcr (void) { target_ulong val; if (unlikely(env->dcr_read == NULL)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - else if (unlikely((*env->dcr_read)(env->dcr_env, dcrn, &val) != 0)) + else if (unlikely((*env->dcr_read)(env->dcr_env, T0, &val) != 0)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); else T0 = val; } -void do_4xx_store_dcr (int dcrn) +void do_store_dcr (void) { if (unlikely(env->dcr_write == NULL)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); - else if (unlikely((*env->dcr_write)(env->dcr_env, dcrn, T0) != 0)) + else if (unlikely((*env->dcr_write)(env->dcr_env, T0, T1) != 0)) do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG); } diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index f819a0d36c..abc295a4da 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -117,9 +117,7 @@ void do_td (int flags); #if !defined(CONFIG_USER_ONLY) void do_rfi (void); #if defined(TARGET_PPC64) -void do_rfi_32 (void); void do_rfid (void); -void do_rfid_32 (void); #endif void do_tlbia (void); void do_tlbie (void); @@ -158,9 +156,12 @@ void do_op_602_mfrom (void); void do_405_check_ov (void); void do_405_check_sat (void); #if !defined(CONFIG_USER_ONLY) -void do_4xx_load_dcr (int dcrn); -void do_4xx_store_dcr (int dcrn); -void do_4xx_rfci (void); +void do_load_dcr (void); +void do_store_dcr (void); +void do_40x_rfci (void); +void do_rfci (void); +void do_rfdi (void); +void do_rfmci (void); void do_4xx_tlbre_lo (void); void do_4xx_tlbre_hi (void); void do_4xx_tlbsx (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 7d382d6cab..2d9a346ed5 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -2861,12 +2861,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) RET_PRIVOPC(ctx); return; } -#if defined(TARGET_PPC64) - if (!ctx->sf_mode) - gen_op_rfi_32(); - else -#endif - gen_op_rfi(); + gen_op_rfi(); RET_CHG_FLOW(ctx); #endif } @@ -2882,10 +2877,7 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW) RET_PRIVOPC(ctx); return; } - if (!ctx->sf_mode) - gen_op_rfid_32(); - else - gen_op_rfid(); + gen_op_rfid(); RET_CHG_FLOW(ctx); #endif } @@ -4423,7 +4415,8 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) RET_PRIVREG(ctx); return; } - gen_op_4xx_load_dcr(dcrn); + gen_op_set_T0(dcrn); + gen_op_load_dcr(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -4440,8 +4433,41 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) RET_PRIVREG(ctx); return; } - gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_4xx_store_dcr(dcrn); + gen_op_set_T0(dcrn); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_store_dcr(); +#endif +} + +/* mfdcrx */ +GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_dcr(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* mtdcrx */ +GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_store_dcr(); #endif } @@ -4513,7 +4539,7 @@ GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) } /* rfci (supervisor only) */ -GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) +GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4523,14 +4549,59 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) return; } /* Restore CPU state */ - gen_op_4xx_rfci(); + gen_op_40x_rfci(); RET_CHG_FLOW(ctx); #endif } +GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_rfci(); + RET_CHG_FLOW(ctx); +#endif +} + +/* BookE specific */ +GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_rfdi(); + RET_CHG_FLOW(ctx); +#endif +} + +GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_rfmci(); + RET_CHG_FLOW(ctx); +#endif +} /* TLB management - PowerPC 405 implementation */ /* tlbre */ -GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) +GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4558,7 +4629,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) } /* tlbsx - tlbsx. */ -GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON) +GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); @@ -4615,7 +4686,7 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) return; } gen_op_load_gpr_T0(rD(ctx->opcode)); - gen_op_4xx_wrte(); + gen_op_wrte(); RET_EXCP(ctx, EXCP_MTMSR, 0); #endif } @@ -4631,7 +4702,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) return; } gen_op_set_T0(ctx->opcode & 0x00010000); - gen_op_4xx_wrte(); + gen_op_wrte(); RET_EXCP(ctx, EXCP_MTMSR, 0); #endif }