QEMU timer subsytem supports timeouts only upto INT64_MAX.
However WCV value geater than that will cause integer overflow
and timer will fire/expire immediately.
It looks like Windows tries to use SBSA watchdog when it's
exposed in GTDT ACPI table.
But instead of using WRR to refresh WCV with configured WOR,
it does direct load into WCV (probably as a means to
reschedule timer). While it's not against spec,
Windows does write following values:
sbsa_gwdt_control_write [0x8] <- 0xffffffff
sbsa_gwdt_control_write [0x0] <- 0x1
sbsa_gwdt_control_write [0x14] <- 0xffffffff
sbsa_gwdt_control_write [0x10] <- 0xa906ca28
sbsa_gwdt_control_write [0x14] <- 0xecb1
1st intermediate write into 0x14 (WCVU),
puts WCV into timer overflow range,
triggering TimeoutRefresh and WS0 and WS1 asseritons.
Clamp WCV to INT64_MAX to avoid timer API overflow.
It prevents unexpected Windows reboots by watchdog.
PS:
Arguably Windows SBSA GWDT driver is broken,
as it:
* sets WCV too far in the future so watchdog
would never trigger in practice,
* and typical watchdog flow for explict referesh
also broken due to:
1. small WOR value for explicit refresh (~4sec)
2. never triggering explicit refresh (WRR or other)
Signed-off-by: Igor Mammedov <[email protected]>
---
hw/watchdog/sbsa_gwdt.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index 7fec61b7b0..b1bce5008d 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -122,6 +122,8 @@ static void sbsa_gwdt_update_timer(SBSA_GWDTState *s,
WdtRefreshType rtype)
}
timeout = (uint64_t)s->wcvu << 32 | s->wcvl;
+ /* clamp timeout to INT64_MAX to avoid timer overflow */
+ timeout &= INT64_MAX;
timer_mod(s->timer, timeout);
}
--
2.47.3