qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] target-xtensa: fix guest hang on masked CCOMPAR


From: Blue Swirl
Subject: Re: [Qemu-devel] [PATCH] target-xtensa: fix guest hang on masked CCOMPARE interrupt
Date: Sat, 15 Oct 2011 21:36:12 +0000

Thanks, applied.

On Mon, Oct 10, 2011 at 2:25 AM, Max Filippov <address@hidden> wrote:
> 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 <address@hidden>
> ---
>  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
> --
> 1.7.6.4
>
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]