Commit a7410b601e for qemu.org
commit a7410b601ee2568c904aac862b947fb3dc22e1eb
Author: Peter Maydell <peter.maydell@linaro.org>
Date: Fri May 8 17:20:10 2026 +0100
hw/misc/bcm2835_control.c: Don't assert on local timer zero reload value
The bcm2836 local timer has a basic "counts down, fires at zero,
and reloads to programmed value to count down again" functionality,
as documented in
https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
The documentation is very sparse and doesn't say what actually
happens if the guest programs the reload value to zero. Currently we
trip an assert in this case.
Instead, log this as a guest error and disable the timer (which seems
a reasonable guess -- effectively the timer will stop counting).
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3395
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20260508162013.2751001-2-peter.maydell@linaro.org
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
index f1deafaf7a..d6c6057cd2 100644
--- a/hw/intc/bcm2836_control.c
+++ b/hw/intc/bcm2836_control.c
@@ -197,12 +197,21 @@ static void bcm2836_control_local_timer_set_next(void *opaque)
{
BCM2836ControlState *s = opaque;
uint64_t next_event;
-
- assert(LOCALTIMER_VALUE(s->local_timer_control) > 0);
+ uint64_t reload_value = LOCALTIMER_VALUE(s->local_timer_control);
+
+ if (reload_value == 0) {
+ /*
+ * Spec doesn't say what happens in this case; treat as a
+ * guest error and stop the timer running.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: local timer reload value is 0\n",
+ __func__);
+ timer_del(&s->timer);
+ return;
+ }
next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(LOCALTIMER_VALUE(s->local_timer_control),
- NANOSECONDS_PER_SECOND, LOCALTIMER_FREQ);
+ muldiv64(reload_value, NANOSECONDS_PER_SECOND, LOCALTIMER_FREQ);
timer_mod(&s->timer, next_event);
}