[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] target/arm: Add overflow check for gt_recalc_timer
From: |
Leonid Komarianskyi |
Subject: |
[PATCH] target/arm: Add overflow check for gt_recalc_timer |
Date: |
Thu, 6 Apr 2023 15:16:11 +0000 |
If gt_timer is enabled before cval initialization on a virtualized
setup on QEMU, cval equals (UINT64_MAX - 1). Adding an offset value
to this causes an overflow that sets timer into the past, which leads
to infinite loop, because this timer fires immediately and calls
gt_recalc_timer() once more, which in turn sets the timer into the
past again and as a result, QEMU hangs. This patch adds check for
overflowing of the nexttick variable.
Suggested-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
Co-Authored-By: Dmytro Firsov <dmytro_firsov@epam.com>
Signed-off-by: Leonid Komarianskyi <leonid_komarianskyi@epam.com>
---
target/arm/helper.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 2297626bfb..2fbba15040 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2618,6 +2618,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
int istatus = count - offset >= gt->cval;
uint64_t nexttick;
int irqstate;
+ bool nexttick_overflow = false;
gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
@@ -2630,6 +2631,16 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
} else {
/* Next transition is when we hit cval */
nexttick = gt->cval + offset;
+ if (nexttick < offset) {
+ /*
+ * If gt->cval value is close to UINT64_MAX then adding
+ * to it offset can lead to overflow of nexttick variable.
+ * So, this check tests that arguments sum is less than any
+ * addend, and in case it is overflowed we have to mod timer
+ * to INT64_MAX.
+ */
+ nexttick_overflow = true;
+ }
}
/*
* Note that the desired next expiry time might be beyond the
@@ -2637,7 +2648,8 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
* set the timer for as far in the future as possible. When the
* timer expires we will reset the timer for any remaining period.
*/
- if (nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu)) {
+ if ((nexttick > INT64_MAX / gt_cntfrq_period_ns(cpu))
+ || nexttick_overflow) {
timer_mod_ns(cpu->gt_timer[timeridx], INT64_MAX);
} else {
timer_mod(cpu->gt_timer[timeridx], nexttick);
--
2.25.1
- [PATCH] target/arm: Add overflow check for gt_recalc_timer,
Leonid Komarianskyi <=