aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/arm/helper.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index ff19709..2746d3f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2646,11 +2646,28 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
if (istatus) {
- /* Next transition is when count rolls back over to zero */
- nexttick = UINT64_MAX;
+ /*
+ * Next transition is when (count - offset) rolls back over to 0.
+ * If offset > count then this is when count == offset;
+ * if offset <= count then this is when count == offset + 2^64
+ * For the latter case we set nexttick to an "as far in future
+ * as possible" value and let the code below handle it.
+ */
+ if (offset > count) {
+ nexttick = offset;
+ } else {
+ nexttick = UINT64_MAX;
+ }
} else {
- /* Next transition is when we hit cval */
- nexttick = gt->cval + offset;
+ /*
+ * Next transition is when (count - offset) == cval, i.e.
+ * when count == (cval + offset).
+ * If that would overflow, then again we set up the next interrupt
+ * for "as far in the future as possible" for the code below.
+ */
+ if (uadd64_overflow(gt->cval, offset, &nexttick)) {
+ nexttick = UINT64_MAX;
+ }
}
/*
* Note that the desired next expiry time might be beyond the