From patchwork Mon Oct 10 02:25:04 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Filippov X-Patchwork-Id: 118631 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1837FB6FA5 for ; Mon, 10 Oct 2011 13:25:26 +1100 (EST) Received: from localhost ([::1]:48278 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RD5YR-0002dy-9B for incoming@patchwork.ozlabs.org; Sun, 09 Oct 2011 22:25:23 -0400 Received: from eggs.gnu.org ([140.186.70.92]:34045) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RD5YL-0002di-SU for qemu-devel@nongnu.org; Sun, 09 Oct 2011 22:25:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RD5YK-0002Cx-Le for qemu-devel@nongnu.org; Sun, 09 Oct 2011 22:25:17 -0400 Received: from [188.134.19.124] (port=59858 helo=octofox.metropolis) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RD5YK-0002Cj-9a for qemu-devel@nongnu.org; Sun, 09 Oct 2011 22:25:16 -0400 Received: from octofox.metropolis (localhost [127.0.0.1]) by octofox.metropolis (8.14.5/8.14.5) with ESMTP id p9A2PD7u003208; Mon, 10 Oct 2011 06:25:13 +0400 Received: (from jcmvbkbc@localhost) by octofox.metropolis (8.14.5/8.14.5/Submit) id p9A2PDiW003207; Mon, 10 Oct 2011 06:25:13 +0400 From: Max Filippov To: qemu-devel@nongnu.org Date: Mon, 10 Oct 2011 06:25:04 +0400 Message-Id: <1318213505-3168-1-git-send-email-jcmvbkbc@gmail.com> X-Mailer: git-send-email 1.7.6.4 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 188.134.19.124 Cc: jcmvbkbc@gmail.com Subject: [Qemu-devel] [PATCH] target-xtensa: fix guest hang on masked CCOMPARE interrupt X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- hw/xtensa_pic.c | 27 ++++++++++++++++++- target-xtensa/cpu.h | 1 + target-xtensa/op_helper.c | 18 ++---------- tests/xtensa/test_timer.S | 63 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 16 deletions(-) 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) diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 339075d..966f515 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -313,6 +313,7 @@ void check_interrupts(CPUXtensaState *s); void xtensa_irq_init(CPUState *env); void xtensa_advance_ccount(CPUState *env, uint32_t d); void xtensa_timer_irq(CPUState *env, uint32_t id, uint32_t active); +void xtensa_rearm_ccompare_timer(CPUState *env); int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc); void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); void xtensa_sync_window_from_phys(CPUState *env); diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index 64847fc..0605611 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -370,23 +370,11 @@ void HELPER(waiti)(uint32_t pc, uint32_t intlevel) return; } - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { - 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, qemu_get_clock_ns(vm_clock) + - muldiv64(wake_ccount - env->sregs[CCOUNT], - 1000000, env->config->clock_freq_khz)); - } env->halt_clock = qemu_get_clock_ns(vm_clock); env->halted = 1; + if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { + xtensa_rearm_ccompare_timer(env); + } HELPER(exception)(EXCP_HLT); } diff --git a/tests/xtensa/test_timer.S b/tests/xtensa/test_timer.S index ede6395..1041cc6 100644 --- a/tests/xtensa/test_timer.S +++ b/tests/xtensa/test_timer.S @@ -14,6 +14,7 @@ test ccompare wsr a2, intenable rsr a2, interrupt wsr a2, intclear + movi a2, 0 wsr a2, ccompare1 wsr a2, ccompare2 @@ -37,6 +38,7 @@ test ccompare0_interrupt wsr a2, intenable rsr a2, interrupt wsr a2, intclear + movi a2, 0 wsr a2, ccompare1 wsr a2, ccompare2 @@ -66,6 +68,7 @@ test ccompare1_interrupt wsr a2, intenable rsr a2, interrupt wsr a2, intclear + movi a2, 0 wsr a2, ccompare0 wsr a2, ccompare2 @@ -92,6 +95,7 @@ test ccompare2_interrupt wsr a2, intenable rsr a2, interrupt wsr a2, intclear + movi a2, 0 wsr a2, ccompare0 wsr a2, ccompare1 @@ -112,4 +116,63 @@ test ccompare2_interrupt 2: test_end +test ccompare_interrupt_masked + set_vector kernel, 2f + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + movi a2, 0 + wsr a2, ccompare2 + + movi a3, 40 + rsr a2, ccount + addi a2, a2, 20 + wsr a2, ccompare1 + addi a2, a2, 20 + wsr a2, ccompare0 + rsync + rsr a2, interrupt + assert eqi, a2, 0 + + movi a2, 0x40 + wsr a2, intenable + rsil a2, 0 + loop a3, 1f + nop +1: + test_fail +2: + rsr a2, exccause + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +test_end + +test ccompare_interrupt_masked_waiti + set_vector kernel, 2f + movi a2, 0 + wsr a2, intenable + rsr a2, interrupt + wsr a2, intclear + movi a2, 0 + wsr a2, ccompare2 + + movi a3, 40 + rsr a2, ccount + addi a2, a2, 20 + wsr a2, ccompare1 + addi a2, a2, 20 + wsr a2, ccompare0 + rsync + rsr a2, interrupt + assert eqi, a2, 0 + + movi a2, 0x40 + wsr a2, intenable + waiti 0 + test_fail +2: + rsr a2, exccause + assert eqi, a2, 4 /* LEVEL1_INTERRUPT_CAUSE */ +test_end + test_suite_end