target/microblaze: Collected fixes for env->iflags
There are several problems here that can result in soft lockup,
depending on exactly where an interrupt or exception is delivered:
Include BIMM_FLAG in IFLAGS_TB_MASK, since it needs to follow D_FLAG.
Ensure that iflags is 0 when entering an interrupt/exception handler.
Add mb_cpu_synchronize_from_tb to restore iflags from tb->flags.
The change to t_sync_flags is cosmetic, but makes the code clearer.
This fixes the reported regression in acceptance/replay_kernel.py.
Fixes: 683a247ed7
("target/microblaze: Store "current" iflags in insn_start")
Tested-by: Thomas Huth <thuth@redhat.com>
Reported-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200904190842.2282109-2-richard.henderson@linaro.org>
Signed-off-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
parent
cc9962d8ea
commit
88e74b6122
|
@ -80,6 +80,16 @@ static void mb_cpu_set_pc(CPUState *cs, vaddr value)
|
||||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||||
|
|
||||||
cpu->env.pc = value;
|
cpu->env.pc = value;
|
||||||
|
/* Ensure D_FLAG and IMM_FLAG are clear for the new PC */
|
||||||
|
cpu->env.iflags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mb_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
||||||
|
{
|
||||||
|
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||||
|
|
||||||
|
cpu->env.pc = tb->pc;
|
||||||
|
cpu->env.iflags = tb->flags & IFLAGS_TB_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mb_cpu_has_work(CPUState *cs)
|
static bool mb_cpu_has_work(CPUState *cs)
|
||||||
|
@ -321,6 +331,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
cc->cpu_exec_interrupt = mb_cpu_exec_interrupt;
|
cc->cpu_exec_interrupt = mb_cpu_exec_interrupt;
|
||||||
cc->dump_state = mb_cpu_dump_state;
|
cc->dump_state = mb_cpu_dump_state;
|
||||||
cc->set_pc = mb_cpu_set_pc;
|
cc->set_pc = mb_cpu_set_pc;
|
||||||
|
cc->synchronize_from_tb = mb_cpu_synchronize_from_tb;
|
||||||
cc->gdb_read_register = mb_cpu_gdb_read_register;
|
cc->gdb_read_register = mb_cpu_gdb_read_register;
|
||||||
cc->gdb_write_register = mb_cpu_gdb_write_register;
|
cc->gdb_write_register = mb_cpu_gdb_write_register;
|
||||||
cc->tlb_fill = mb_cpu_tlb_fill;
|
cc->tlb_fill = mb_cpu_tlb_fill;
|
||||||
|
|
|
@ -270,7 +270,8 @@ struct CPUMBState {
|
||||||
#define D_FLAG (1 << 19) /* Bit in ESR. */
|
#define D_FLAG (1 << 19) /* Bit in ESR. */
|
||||||
|
|
||||||
/* TB dependent CPUMBState. */
|
/* TB dependent CPUMBState. */
|
||||||
#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)
|
#define IFLAGS_TB_MASK (D_FLAG | BIMM_FLAG | IMM_FLAG | \
|
||||||
|
DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)
|
||||||
#define MSR_TB_MASK (MSR_UM | MSR_VM | MSR_EE)
|
#define MSR_TB_MASK (MSR_UM | MSR_VM | MSR_EE)
|
||||||
|
|
||||||
uint32_t iflags;
|
uint32_t iflags;
|
||||||
|
|
|
@ -113,7 +113,10 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||||
uint32_t t, msr = mb_cpu_read_msr(env);
|
uint32_t t, msr = mb_cpu_read_msr(env);
|
||||||
|
|
||||||
/* IMM flag cannot propagate across a branch and into the dslot. */
|
/* IMM flag cannot propagate across a branch and into the dslot. */
|
||||||
assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
|
assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG));
|
||||||
|
/* BIMM flag cannot be set without D_FLAG. */
|
||||||
|
assert((env->iflags & (D_FLAG | BIMM_FLAG)) != BIMM_FLAG);
|
||||||
|
/* RTI flags are private to translate. */
|
||||||
assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
|
assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
|
||||||
env->res_addr = RES_ADDR_NONE;
|
env->res_addr = RES_ADDR_NONE;
|
||||||
switch (cs->exception_index) {
|
switch (cs->exception_index) {
|
||||||
|
@ -146,7 +149,7 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||||
env->pc, env->ear,
|
env->pc, env->ear,
|
||||||
env->esr, env->iflags);
|
env->esr, env->iflags);
|
||||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||||
env->iflags &= ~(IMM_FLAG | D_FLAG);
|
env->iflags = 0;
|
||||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -186,14 +189,14 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||||
"exception at pc=%x ear=%" PRIx64 " iflags=%x\n",
|
"exception at pc=%x ear=%" PRIx64 " iflags=%x\n",
|
||||||
env->pc, env->ear, env->iflags);
|
env->pc, env->ear, env->iflags);
|
||||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||||
env->iflags &= ~(IMM_FLAG | D_FLAG);
|
env->iflags = 0;
|
||||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXCP_IRQ:
|
case EXCP_IRQ:
|
||||||
assert(!(msr & (MSR_EIP | MSR_BIP)));
|
assert(!(msr & (MSR_EIP | MSR_BIP)));
|
||||||
assert(msr & MSR_IE);
|
assert(msr & MSR_IE);
|
||||||
assert(!(env->iflags & D_FLAG));
|
assert(!(env->iflags & (D_FLAG | IMM_FLAG)));
|
||||||
|
|
||||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||||
|
|
||||||
|
@ -226,13 +229,14 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||||
mb_cpu_write_msr(env, msr);
|
mb_cpu_write_msr(env, msr);
|
||||||
|
|
||||||
env->regs[14] = env->pc;
|
env->regs[14] = env->pc;
|
||||||
|
env->iflags = 0;
|
||||||
env->pc = cpu->cfg.base_vectors + 0x10;
|
env->pc = cpu->cfg.base_vectors + 0x10;
|
||||||
//log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
//log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXCP_HW_BREAK:
|
case EXCP_HW_BREAK:
|
||||||
assert(!(env->iflags & IMM_FLAG));
|
assert(!(env->iflags & (D_FLAG | IMM_FLAG)));
|
||||||
assert(!(env->iflags & D_FLAG));
|
|
||||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||||
qemu_log_mask(CPU_LOG_INT,
|
qemu_log_mask(CPU_LOG_INT,
|
||||||
"break at pc=%x msr=%x %x iflags=%x\n",
|
"break at pc=%x msr=%x %x iflags=%x\n",
|
||||||
|
@ -242,6 +246,7 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||||
msr |= t;
|
msr |= t;
|
||||||
msr |= MSR_BIP;
|
msr |= MSR_BIP;
|
||||||
env->regs[16] = env->pc;
|
env->regs[16] = env->pc;
|
||||||
|
env->iflags = 0;
|
||||||
env->pc = cpu->cfg.base_vectors + 0x18;
|
env->pc = cpu->cfg.base_vectors + 0x18;
|
||||||
mb_cpu_write_msr(env, msr);
|
mb_cpu_write_msr(env, msr);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -91,8 +91,8 @@ static int typeb_imm(DisasContext *dc, int x)
|
||||||
static void t_sync_flags(DisasContext *dc)
|
static void t_sync_flags(DisasContext *dc)
|
||||||
{
|
{
|
||||||
/* Synch the tb dependent flags between translator and runtime. */
|
/* Synch the tb dependent flags between translator and runtime. */
|
||||||
if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) {
|
if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
|
||||||
tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK);
|
tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue