qemu-devel
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]