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
This commit is contained in:
j_mayer 2007-03-30 10:22:46 +00:00
parent 363be49c86
commit a42bd6ccdf
4 changed files with 196 additions and 80 deletions

View File

@ -1821,23 +1821,11 @@ void OPPROTO op_rfi (void)
} }
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
void OPPROTO op_rfi_32 (void)
{
do_rfi_32();
RETURN();
}
void OPPROTO op_rfid (void) void OPPROTO op_rfid (void)
{ {
do_rfid(); do_rfid();
RETURN(); RETURN();
} }
void OPPROTO op_rfid_32 (void)
{
do_rfid_32();
RETURN();
}
#endif #endif
#endif #endif
@ -2309,28 +2297,46 @@ void OPPROTO op_405_check_satu (void)
} }
#if !defined(CONFIG_USER_ONLY) #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(); RETURN();
} }
void OPPROTO op_4xx_store_dcr (void) void OPPROTO op_store_dcr (void)
{ {
do_4xx_store_dcr(PARAM1); do_store_dcr();
RETURN(); RETURN();
} }
/* Return from critical interrupt : /* Return from critical interrupt :
* same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1 * 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(); 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; msr_ee = T0 >> 16;
RETURN(); RETURN();

View File

@ -881,12 +881,17 @@ void do_fcmpo (void)
#if !defined (CONFIG_USER_ONLY) #if !defined (CONFIG_USER_ONLY)
void do_rfi (void) 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) #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 #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 #endif
#if defined (DEBUG_OP) #if defined (DEBUG_OP)
dump_rfi(); dump_rfi();
@ -895,33 +900,15 @@ void do_rfi (void)
} }
#if defined(TARGET_PPC64) #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) void do_rfid (void)
{ {
env->nip = (target_ulong)(env->spr[SPR_SRR0] & ~0x00000003); if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) {
T0 = (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL); env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003);
do_store_msr(env, T0); do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
#if defined (DEBUG_OP) } else {
dump_rfi(); env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
#endif do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
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 defined (DEBUG_OP) #if defined (DEBUG_OP)
dump_rfi(); dump_rfi();
#endif #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 & 0x08)) ||
((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) || ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) ||
((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) || ((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); do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
}
} }
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
@ -1196,34 +1184,84 @@ void do_405_check_sat (void)
} }
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void do_4xx_rfci (void) void do_40x_rfci (void)
{ {
env->nip = env->spr[SPR_40x_SRR2]; env->nip = env->spr[SPR_40x_SRR2];
T0 = env->spr[SPR_40x_SRR3] & ~0xFFFF0000; do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000);
do_store_msr(env, T0);
#if defined (DEBUG_OP) #if defined (DEBUG_OP)
dump_rfi(); dump_rfi();
#endif #endif
env->interrupt_request = CPU_INTERRUPT_EXITTB; 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; target_ulong val;
if (unlikely(env->dcr_read == NULL)) if (unlikely(env->dcr_read == NULL))
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); 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); do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
else else
T0 = val; T0 = val;
} }
void do_4xx_store_dcr (int dcrn) void do_store_dcr (void)
{ {
if (unlikely(env->dcr_write == NULL)) if (unlikely(env->dcr_write == NULL))
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL); 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); do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
} }

View File

@ -117,9 +117,7 @@ void do_td (int flags);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void do_rfi (void); void do_rfi (void);
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
void do_rfi_32 (void);
void do_rfid (void); void do_rfid (void);
void do_rfid_32 (void);
#endif #endif
void do_tlbia (void); void do_tlbia (void);
void do_tlbie (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_ov (void);
void do_405_check_sat (void); void do_405_check_sat (void);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void do_4xx_load_dcr (int dcrn); void do_load_dcr (void);
void do_4xx_store_dcr (int dcrn); void do_store_dcr (void);
void do_4xx_rfci (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_lo (void);
void do_4xx_tlbre_hi (void); void do_4xx_tlbre_hi (void);
void do_4xx_tlbsx (void); void do_4xx_tlbsx (void);

View File

@ -2861,12 +2861,7 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
return; return;
} }
#if defined(TARGET_PPC64) gen_op_rfi();
if (!ctx->sf_mode)
gen_op_rfi_32();
else
#endif
gen_op_rfi();
RET_CHG_FLOW(ctx); RET_CHG_FLOW(ctx);
#endif #endif
} }
@ -2882,10 +2877,7 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
return; return;
} }
if (!ctx->sf_mode) gen_op_rfid();
gen_op_rfid_32();
else
gen_op_rfid();
RET_CHG_FLOW(ctx); RET_CHG_FLOW(ctx);
#endif #endif
} }
@ -4423,7 +4415,8 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
RET_PRIVREG(ctx); RET_PRIVREG(ctx);
return; return;
} }
gen_op_4xx_load_dcr(dcrn); gen_op_set_T0(dcrn);
gen_op_load_dcr();
gen_op_store_T0_gpr(rD(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode));
#endif #endif
} }
@ -4440,8 +4433,41 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
RET_PRIVREG(ctx); RET_PRIVREG(ctx);
return; return;
} }
gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_set_T0(dcrn);
gen_op_4xx_store_dcr(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 #endif
} }
@ -4513,7 +4539,7 @@ GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
} }
/* rfci (supervisor only) */ /* 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) #if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
@ -4523,14 +4549,59 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON)
return; return;
} }
/* Restore CPU state */ /* Restore CPU state */
gen_op_4xx_rfci(); gen_op_40x_rfci();
RET_CHG_FLOW(ctx); RET_CHG_FLOW(ctx);
#endif #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 */ /* TLB management - PowerPC 405 implementation */
/* tlbre */ /* 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) #if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
@ -4558,7 +4629,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON)
} }
/* tlbsx - tlbsx. */ /* 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) #if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx); RET_PRIVOPC(ctx);
@ -4615,7 +4686,7 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
return; return;
} }
gen_op_load_gpr_T0(rD(ctx->opcode)); gen_op_load_gpr_T0(rD(ctx->opcode));
gen_op_4xx_wrte(); gen_op_wrte();
RET_EXCP(ctx, EXCP_MTMSR, 0); RET_EXCP(ctx, EXCP_MTMSR, 0);
#endif #endif
} }
@ -4631,7 +4702,7 @@ GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
return; return;
} }
gen_op_set_T0(ctx->opcode & 0x00010000); gen_op_set_T0(ctx->opcode & 0x00010000);
gen_op_4xx_wrte(); gen_op_wrte();
RET_EXCP(ctx, EXCP_MTMSR, 0); RET_EXCP(ctx, EXCP_MTMSR, 0);
#endif #endif
} }