diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2020-09-04 12:08:24 -0700 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2020-09-07 12:34:17 +0200 |
commit | 88e74b6122bb40852b1c98befd47a572f0c06930 (patch) | |
tree | ffc95474b4531f624455deba98b68409cc98fe30 | |
parent | cc9962d8ea80b39118d921109fd2f8db308e1d4a (diff) |
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: 683a247ed7a4 ("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>
-rw-r--r-- | target/microblaze/cpu.c | 11 | ||||
-rw-r--r-- | target/microblaze/cpu.h | 3 | ||||
-rw-r--r-- | target/microblaze/helper.c | 17 | ||||
-rw-r--r-- | target/microblaze/translate.c | 4 |
4 files changed, 26 insertions, 9 deletions
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 67017ecc33..6392524135 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -80,6 +80,16 @@ static void mb_cpu_set_pc(CPUState *cs, vaddr value) MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 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) @@ -321,6 +331,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) cc->cpu_exec_interrupt = mb_cpu_exec_interrupt; cc->dump_state = mb_cpu_dump_state; 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_write_register = mb_cpu_gdb_write_register; cc->tlb_fill = mb_cpu_tlb_fill; diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index d11b6fa995..a25a2b427f 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -270,7 +270,8 @@ struct CPUMBState { #define D_FLAG (1 << 19) /* Bit in ESR. */ /* 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) uint32_t iflags; diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 48547385b0..00090526da 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -113,7 +113,10 @@ void mb_cpu_do_interrupt(CPUState *cs) uint32_t t, msr = mb_cpu_read_msr(env); /* 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))); env->res_addr = RES_ADDR_NONE; switch (cs->exception_index) { @@ -146,7 +149,7 @@ void mb_cpu_do_interrupt(CPUState *cs) env->pc, env->ear, env->esr, env->iflags); 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; break; @@ -186,14 +189,14 @@ void mb_cpu_do_interrupt(CPUState *cs) "exception at pc=%x ear=%" PRIx64 " iflags=%x\n", env->pc, env->ear, env->iflags); 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; break; case EXCP_IRQ: assert(!(msr & (MSR_EIP | MSR_BIP))); assert(msr & MSR_IE); - assert(!(env->iflags & D_FLAG)); + assert(!(env->iflags & (D_FLAG | IMM_FLAG))); t = (msr & (MSR_VM | MSR_UM)) << 1; @@ -226,13 +229,14 @@ void mb_cpu_do_interrupt(CPUState *cs) mb_cpu_write_msr(env, msr); env->regs[14] = env->pc; + env->iflags = 0; env->pc = cpu->cfg.base_vectors + 0x10; //log_cpu_state_mask(CPU_LOG_INT, cs, 0); break; case EXCP_HW_BREAK: - assert(!(env->iflags & IMM_FLAG)); - assert(!(env->iflags & D_FLAG)); + assert(!(env->iflags & (D_FLAG | IMM_FLAG))); + t = (msr & (MSR_VM | MSR_UM)) << 1; qemu_log_mask(CPU_LOG_INT, "break at pc=%x msr=%x %x iflags=%x\n", @@ -242,6 +246,7 @@ void mb_cpu_do_interrupt(CPUState *cs) msr |= t; msr |= MSR_BIP; env->regs[16] = env->pc; + env->iflags = 0; env->pc = cpu->cfg.base_vectors + 0x18; mb_cpu_write_msr(env, msr); break; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index a377818b5e..a8a3249185 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -91,8 +91,8 @@ static int typeb_imm(DisasContext *dc, int x) static void t_sync_flags(DisasContext *dc) { /* Synch the tb dependent flags between translator and runtime. */ - if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) { - tcg_gen_movi_i32(cpu_iflags, dc->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 & IFLAGS_TB_MASK); } } |