arch/x86_64: do not wrap the HPET oneshot on a deadline that has passed.
Some checks failed
Build Documentation / build-html (push) Waiting to run
MemBrowse Memory Report / changes-filter (push) Waiting to run
MemBrowse Memory Report / load-targets (push) Waiting to run
MemBrowse Memory Report / identical (push) Blocked by required conditions
MemBrowse Memory Report / analyze (push) Blocked by required conditions
Docker-Linux / push (push) Has been cancelled

intel64_timer_start_absolute() computed "expected - current_us" unsigned.  A
watchdog started with a delay of zero asks for a deadline that is already
current, the subtraction wraps to nearly 2^64, and the comparator is set so
far ahead that the timer never fires.  The CONFIG_INTEL64_HPET_MIN_DELAY
clamp in intel64_oneshot_start() cannot help: the wrapped value is enormous,
not small.

Ask for the shortest delay the hardware can take instead of wrapping, and let
that existing minimum-delay logic pick it.

It presents as ostest hanging in wdog_test with no output and no fault.
apps/testing/ostest/wdog.c:281 calls wdtest_once(&test_wdog, param, 0), and
NSEC2TICK() takes the next few delays (1ns, 10ns, ...) to zero ticks as well;
wdtest_once() then spins forever in its "wait until the callback is triggered
exactly once" loop.

Impact: runtime, ARCH_INTEL64_HPET_ALARM only.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-07-26 17:24:57 +02:00 committed by Alan C. Assis
parent 97dcbc010b
commit 7fd17c9d7c

View file

@ -149,10 +149,14 @@ static void intel64_timer_start_absolute(struct oneshot_lowerhalf_s *lower,
(struct intel64_oneshot_lowerhalf_s *)lower;
irqstate_t flags = spin_lock_irqsave(&g_oneshotlow_spin);
int ret = intel64_oneshot_current(&priv->oneshot, &current_us);
uint64_t delta_us = expected - current_us;
uint64_t delta_us;
DEBUGASSERT(ret == OK);
/* Use the shortest delay when the deadline has passed. */
delta_us = expected > current_us ? expected - current_us : 0;
ts.tv_sec = delta_us / USEC_PER_SEC;
ts.tv_nsec = delta_us % USEC_PER_SEC * 1000ull;
ret = intel64_oneshot_start(&priv->oneshot, intel64_oneshot_handler,