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 <michal.sojka@cvut.cz>
Signed-off-by: Marek Vedral <marek.vedral@gmail.com>
This commit is contained in:
Marek Vedral 2023-04-27 12:39:06 +02:00 committed by Carles Cufí
parent 9e8c00f28c
commit 6068255512

View file

@ -20,6 +20,14 @@ static uint32_t cyc_per_tick;
/ CONFIG_SYS_CLOCK_TICKS_PER_SEC) / CONFIG_SYS_CLOCK_TICKS_PER_SEC)
#endif #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 */ /* the unsigned long cast limits divisors to native CPU register width */
#define cycle_diff_t unsigned long #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 curr_cycle = arm_arch_timer_count();
uint64_t delta_cycles = curr_cycle - last_cycle; 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_cycle += (cycle_diff_t)delta_ticks * CYC_PER_TICK;
last_tick += delta_ticks; last_tick += delta_ticks;