From 60682555120376bf083bd16bff1cce576c352ddc Mon Sep 17 00:00:00 2001 From: Marek Vedral Date: Thu, 27 Apr 2023 12:39:06 +0200 Subject: [PATCH] drivers/timer/arm_arch_timer: Fix cycles overflow with GDB stub If GDBSTUB is enabled and the kernel runs in tickless mode, the timer must not convert the delta cycles to a 32-bit data type (cycle_diff_t in this case). The delta_ticks variable would overflow and the next timeout would be set before the current timestamp, thus generating an interrupt right after leaving the handler. As a result, the system would receive tens of thousands of interrupts per second and would not boot. Cc: Michal Sojka Signed-off-by: Marek Vedral --- drivers/timer/arm_arch_timer.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c index a9a762d9af..718fecea58 100644 --- a/drivers/timer/arm_arch_timer.c +++ b/drivers/timer/arm_arch_timer.c @@ -20,6 +20,14 @@ static uint32_t cyc_per_tick; / CONFIG_SYS_CLOCK_TICKS_PER_SEC) #endif +#if defined(CONFIG_GDBSTUB) +/* When interactively debugging, the cycle diff can overflow 32-bit variable */ +#define TO_CYCLE_DIFF(x) (x) +#else +/* Convert to 32-bit for fast division */ +#define TO_CYCLE_DIFF(x) ((cycle_diff_t)(x)) +#endif + /* the unsigned long cast limits divisors to native CPU register width */ #define cycle_diff_t unsigned long @@ -58,7 +66,7 @@ static void arm_arch_timer_compare_isr(const void *arg) uint64_t curr_cycle = arm_arch_timer_count(); uint64_t delta_cycles = curr_cycle - last_cycle; - uint32_t delta_ticks = (cycle_diff_t)delta_cycles / CYC_PER_TICK; + uint32_t delta_ticks = TO_CYCLE_DIFF(delta_cycles) / CYC_PER_TICK; last_cycle += (cycle_diff_t)delta_ticks * CYC_PER_TICK; last_tick += delta_ticks;