diff options
Diffstat (limited to 'target-arm/translate.c')
| -rw-r--r-- | target-arm/translate.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c index 22c35877e5..9f1d740b4e 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7720,10 +7720,16 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) return; case 4: /* dsb */ case 5: /* dmb */ - case 6: /* isb */ ARCH(7); /* We don't emulate caches so these are a no-op. */ return; + case 6: /* isb */ + /* We need to break the TB after this insn to execute + * self-modifying code correctly and also to take + * any pending interrupts immediately. + */ + gen_lookup_tb(s); + return; default: goto illegal_op; } @@ -10030,9 +10036,16 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw break; case 4: /* dsb */ case 5: /* dmb */ - case 6: /* isb */ /* These execute as NOPs. */ break; + case 6: /* isb */ + /* We need to break the TB after this insn + * to execute self-modifying code correctly + * and also to take any pending interrupts + * immediately. + */ + gen_lookup_tb(s); + break; default: goto illegal_op; } @@ -11329,11 +11342,20 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) CPUBreakpoint *bp; QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { if (bp->pc == dc->pc) { - gen_exception_internal_insn(dc, 0, EXCP_DEBUG); - /* Advance PC so that clearing the breakpoint will - invalidate this TB. */ - dc->pc += 2; - goto done_generating; + if (bp->flags & BP_CPU) { + gen_helper_check_breakpoints(cpu_env); + /* End the TB early; it's likely not going to be executed */ + dc->is_jmp = DISAS_UPDATE; + } else { + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); + /* Advance PC so that clearing the breakpoint will + invalidate this TB. */ + /* TODO: Advance PC by correct instruction length to + * avoid disassembler error messages */ + dc->pc += 2; + goto done_generating; + } + break; } } } |