diff options
Diffstat (limited to 'target-arm/translate-a64.c')
-rw-r--r-- | target-arm/translate-a64.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index e65e309535..19f9d8d2c8 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1230,9 +1230,15 @@ static void handle_sync(DisasContext *s, uint32_t insn, return; case 4: /* DSB */ case 5: /* DMB */ - case 6: /* ISB */ /* We don't emulate caches so barriers are no-ops */ return; + case 6: /* ISB */ + /* We need to break the TB after this insn to execute + * a self-modified code correctly and also to take + * any pending interrupts immediately. + */ + s->is_jmp = DISAS_UPDATE; + return; default: unallocated_encoding(s); return; @@ -11084,11 +11090,18 @@ void gen_intermediate_code_a64(ARMCPU *cpu, 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 likely won't 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. */ + dc->pc += 4; + goto done_generating; + } + break; } } } |