diff options
author | James Hogan <james.hogan@imgtec.com> | 2014-06-17 23:10:26 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-06-18 16:54:30 +0200 |
commit | 4b69c7e265a2c2fd1120c431c5d8d0809d4ec10a (patch) | |
tree | 182e9220adb8d5f9aa505cfeef9fce81031a5ded | |
parent | 00008418aa22700f6c49e794e79f53aeb157d10f (diff) |
target-mips: Reset CPU timer consistently
The MIPS CPU timer (CP0 Count/Compare registers & QEMU timer) is
reset at machine initialisation, including starting the timeout. Both
registers however are placed before mvp in CPUMIPSState so they will
both be zeroed on reset by the memset in mips_cpu_reset() including soon
after init. This doesn't take into account that the timer may be
running, in which case env->CP0_Count will represent the delta against
the VM clock and the timeout will need updating.
At init time (cpu_mips_clock_init()), lets only create the timer.
Setting Count = 1 and starting the timer (cpu_mips_store_count()) can be
done at reset time from cpu_state_reset(), which is after the memset.
There is also no need to set CP0_Compare = 0 as that is already handled
by the memset.
Note that a reset occurs from mips_cpu_realizefn() which is before the
machine init callback has had a chance to set up the CPU interrupts and
the CPU timer, so env->timer will be NULL. This case is handled
explicitly in cpu_mips_store_count(), treating the timer as disabled
(which will also be the right thing to do when KVM support is added).
Reported-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | hw/mips/cputimer.c | 9 | ||||
-rw-r--r-- | target-mips/translate.c | 2 |
2 files changed, 8 insertions, 3 deletions
diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c index c8b4b000cd..6900a745c6 100644 --- a/hw/mips/cputimer.c +++ b/hw/mips/cputimer.c @@ -85,7 +85,12 @@ uint32_t cpu_mips_get_count (CPUMIPSState *env) void cpu_mips_store_count (CPUMIPSState *env, uint32_t count) { - if (env->CP0_Cause & (1 << CP0Ca_DC)) + /* + * This gets called from cpu_state_reset(), potentially before timer init. + * So env->timer may be NULL, which is also the case with KVM enabled so + * treat timer as disabled in that case. + */ + if (env->CP0_Cause & (1 << CP0Ca_DC) || !env->timer) env->CP0_Count = count; else { /* Store new count register */ @@ -142,6 +147,4 @@ static void mips_timer_cb (void *opaque) void cpu_mips_clock_init (CPUMIPSState *env) { env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &mips_timer_cb, env); - env->CP0_Compare = 0; - cpu_mips_store_count(env, 1); } diff --git a/target-mips/translate.c b/target-mips/translate.c index 76deb7b138..d95ab9efe7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -16043,6 +16043,8 @@ void cpu_state_reset(CPUMIPSState *env) /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); + cpu_mips_store_count(env, 1); + if (env->CP0_Config3 & (1 << CP0C3_MT)) { int i; |