aboutsummaryrefslogtreecommitdiff
path: root/hw/timer
diff options
context:
space:
mode:
authorChristian Svensson <bluecmd@google.com>2019-07-01 17:26:17 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-07-01 17:28:59 +0100
commit055762479be1575377ecf2d8fceb9d8df2703d0f (patch)
treef93e04303fc7da74f8889a600dd358518849163f /hw/timer
parent696942b8bc6562a2b23c6ed8ae32ecdeb9bf4b60 (diff)
aspeed/timer: Ensure positive muldiv delta
If the host decrements the counter register that results in a negative delta. This is then passed to muldiv64 which only handles unsigned numbers resulting in bogus results. This fix ensures the delta being operated on is positive. Test case: kexec a kernel using aspeed_timer and it will freeze on the second bootup when the kernel initializes the timer. With this patch that no longer happens and the timer appears to run OK. Signed-off-by: Christian Svensson <bluecmd@google.com> Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Joel Stanley <joel@jms.id.au> Reviewed-by: Andrew Jeffery <andrew@aj.id.au> Message-id: 20190618165311.27066-12-clg@kaod.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/timer')
-rw-r--r--hw/timer/aspeed_timer.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 745eb8608b..29cc5e8070 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -275,7 +275,11 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
uint32_t rate = calculate_rate(t);
- t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+ if (delta >= 0) {
+ t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+ } else {
+ t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
+ }
aspeed_timer_mod(t);
}
break;