summaryrefslogtreecommitdiffstats
path: root/hw/mips_timer.c
diff options
context:
space:
mode:
authorEdgar E. Iglesias2011-01-18 00:12:22 +0100
committerEdgar E. Iglesias2011-01-18 12:28:32 +0100
commite027e1f075afe36698ce55d86f01b7817707c8b6 (patch)
tree303e47d1bb4fff04647449409e67e464dabee573 /hw/mips_timer.c
parentmips: Break out cpu_mips_timer_expire (diff)
downloadqemu-e027e1f075afe36698ce55d86f01b7817707c8b6.tar.gz
qemu-e027e1f075afe36698ce55d86f01b7817707c8b6.tar.xz
qemu-e027e1f075afe36698ce55d86f01b7817707c8b6.zip
mips: Expire late timers when reading cp0_count
When reading cp0_count from a timer with a late trigger that should already have expired, expire it and raise the timer irq. This makes it possible for guest code (e.g, Linux) that first read cp0_count, then compare it with cp0_compare and check for raised timer interrupt lines to run reliably. Acked-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Diffstat (limited to 'hw/mips_timer.c')
-rw-r--r--hw/mips_timer.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index 8c32087541..9c95f282a2 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -69,9 +69,17 @@ uint32_t cpu_mips_get_count (CPUState *env)
if (env->CP0_Cause & (1 << CP0Ca_DC)) {
return env->CP0_Count;
} else {
+ uint64_t now;
+
+ now = qemu_get_clock(vm_clock);
+ if (qemu_timer_pending(env->timer)
+ && qemu_timer_expired(env->timer, now)) {
+ /* The timer has already expired. */
+ cpu_mips_timer_expire(env);
+ }
+
return env->CP0_Count +
- (uint32_t)muldiv64(qemu_get_clock(vm_clock),
- TIMER_FREQ, get_ticks_per_sec());
+ (uint32_t)muldiv64(now, TIMER_FREQ, get_ticks_per_sec());
}
}