From 890c6333b28a4dcbf2a26a5a17b0e71304d5a851 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 10 Oct 2011 06:25:04 +0400 Subject: target-xtensa: fix guest hang on masked CCOMPARE interrupt QEMU timer is used to post CCOMPARE interrupt when the core is halted. If that CCOMPARE interrupt is masked off then the timer must be rearmed in the callback, otherwise it will be rearmed next time the core goes to halt by the waiti instruction. Add test case into timer testsuite. Signed-off-by: Max Filippov Signed-off-by: Blue Swirl --- hw/xtensa_pic.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c index 3033ae2..e5085ea 100644 --- a/hw/xtensa_pic.c +++ b/hw/xtensa_pic.c @@ -116,10 +116,35 @@ void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active) qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active); } +void xtensa_rearm_ccompare_timer(CPUState *env) +{ + int i; + uint32_t wake_ccount = env->sregs[CCOUNT] - 1; + + for (i = 0; i < env->config->nccompare; ++i) { + if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] < + wake_ccount - env->sregs[CCOUNT]) { + wake_ccount = env->sregs[CCOMPARE + i]; + } + } + env->wake_ccount = wake_ccount; + qemu_mod_timer(env->ccompare_timer, env->halt_clock + + muldiv64(wake_ccount - env->sregs[CCOUNT], + 1000000, env->config->clock_freq_khz)); +} + static void xtensa_ccompare_cb(void *opaque) { CPUState *env = opaque; - xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); + + if (env->halted) { + env->halt_clock = qemu_get_clock_ns(vm_clock); + xtensa_advance_ccount(env, env->wake_ccount - env->sregs[CCOUNT]); + if (!cpu_has_work(env)) { + env->sregs[CCOUNT] = env->wake_ccount + 1; + xtensa_rearm_ccompare_timer(env); + } + } } void xtensa_irq_init(CPUState *env) -- cgit v1.1