From: Vladimir Prus <vladimir@codesourcery.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] Fix ptimer_get_count overflow.
Date: Thu, 12 Feb 2009 17:33:43 +0300 [thread overview]
Message-ID: <200902121733.43146.vladimir@codesourcery.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 763 bytes --]
At present, ptimers have a slight inaccuracy that can lead to
overflow. The period is stored as 64.32 fixed point number.
ptimer_reload uses both integer and fractional part of the perion
when computing when the next event should happen. ptimer_get_count,
however, uses only integer part of the period. Therefore, when
ptimer_get_count is called very soon after ptimer_reload the value
returned may be greater than the value ptimer_reload has set.
And if the counter was 0xFFFFFFFF, this may result in overflow.
This was observed in SH4A emulation as "time jumps", where system
time gets magically increased by 10 minutes sometimes.
This patch fixes this. The math is not the most accurate possible,
but it's relatively fast and fixes the problems.
- Volodya
[-- Attachment #2: primer_overflow.diff --]
[-- Type: text/x-diff, Size: 2008 bytes --]
commit f1b78f0ca2b7fe12cdaabcb97c08484d3c26b99f
Author: Vladimir Prus <vladimir@codesourcery.com>
Date: Thu Dec 25 17:20:38 2008 +0300
Fix ptimer_get_count overflow.
* hw/ptimer.c (ptimer_get_count): Don't ignore
fractional part of period.
diff --git a/hw/ptimer.c b/hw/ptimer.c
index 9d38627..9278f83 100644
--- a/hw/ptimer.c
+++ b/hw/ptimer.c
@@ -7,7 +7,7 @@
*/
#include "hw.h"
#include "qemu-timer.h"
-
+#include "host-utils.h"
struct ptimer_state
{
@@ -78,10 +78,41 @@ uint64_t ptimer_get_count(ptimer_state *s)
} else {
uint64_t rem;
uint64_t div;
+ uint32_t frac;
+ int clz1, clz2;
+ int shift;
+
+ /* We need to divide time by period, where time is stored in
+ rem (64-bit integer) and period is stored in period/period_frac
+ (64.32 fixed point). The result should be rounded down, so that
+ we never get the value greater than the timer's limit.
+
+ We normalize both numerator and demoninator by left-shifting
+ until one of them has non-zero MSB, and then do 64-bit division.
+ */
rem = s->next_event - now;
div = s->period;
- counter = rem / div;
+
+ clz1 = clz64(rem);
+ clz2 = clz64(div);
+ shift = clz1 < clz2 ? clz1 : clz2;
+
+ rem <<= shift;
+ div <<= shift;
+ if (shift <= 32)
+ div |= (unsigned long long)(
+ (s->period_frac >> (32 - shift)) & ((1ull << shift) - 1));
+ else
+ div |= (s->period_frac << (shift - 32));
+
+ /* Look at remaining bits of period_frac and round div up if
+ necessary. */
+ frac = s->period_frac << shift;
+ if (frac)
+ div += 1;
+
+ counter = rem/div;
}
} else {
counter = s->delta;
next reply other threads:[~2009-02-12 14:33 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-02-12 14:33 Vladimir Prus [this message]
2009-03-04 9:31 ` [Qemu-devel] Re: Fix ptimer_get_count overflow Vladimir Prus
2009-03-31 14:38 ` Paul Brook
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200902121733.43146.vladimir@codesourcery.com \
--to=vladimir@codesourcery.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).