* [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards
@ 2026-03-03 9:25 Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 01/21] acpi: add API to build WDAT instructions Igor Mammedov
` (21 more replies)
0 siblings, 22 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Changelog:
v2:
* ditch generic '-machine acpi-watchdog' option in favor of
board specific variants:
x86/q35: -machine wdat={on|off}
arm/virt: -device sbsa_gwdt,wdat={on|off}
* arm/virt: add FDT and GTDT ACPI entries for GWDT when it's present
and hide GDTD one when WDAT is enabled.
* arm/virt: add test case for GTDT
* [18-21] optional GWDT cleanup/fixes in handling WCV register update,
make QEMU behave according to spec (at least the way I read it and
it appears MS also read it that way). It fixes Windows 11 reboots when
GWDT is present (without WDAT). With that fixed it's up to MS to fix
their driver to set sane timeout as with the current one wdatchdog
will never trigger.
Windows doesn't ship built-in TCO watchdog driver, and users are
forced to install vendor specific driver(s) if such exists.
However the OS provides a generic watchdog driver that uses
ACPI WDAT table [1] to abstract actual hardware behind it.
The same applies to ARM version of Windows.
This series adds
* WDAT table tailored for TCO watchdog that Q35 already
has as part of ICH9 chipset and a knob to enable it.
* SBSA GWDT to arm/virt machine with WDAT table tailored
for it and necessary tweaks to GWDT to make usable
with WDAT driver.
* in addition to WDAT, it also adds native variant
with GWDT described in FDT and DTDT
(broken on Windows/works on linux).
Guest OS WDAT support is present since Windows Vista and Linux since 2016[2].
One can test it launching VM with following options:
* x86:
-machine q35,wdat=on
* arm/virt:
-device sbsa_gwdt,wdat=on
to trace access to TCO registers one can add to CLI:
-trace "tco_*"
to trace access to GWDT registers one can add to CLI:
-trace "sbsa_gwdt*"
To verify that guest uses WDAT (both Windows and Linux would use it if present),
* on linux make sure that watchdog service is configured/enabled
(use wdctl to check what watchdog device is in use) and then
trigger kernel panic with command:
echo c > /proc/sysrq-trigger
* on Windows kill svchost process, running cmd in admin mode:
taskkill /f /im svchost.exe
Tested with WS2025 & RHEL9.6 & Fedora 43 (aarch64)
git tree at: https://gitlab.com/imammedo/qemu/-/commits/gwdt_v2
1) http://msdn.microsoft.com/en-us/windows/hardware/gg463320.aspx
2) https://lwn.net/Articles/700524/
PS:
previous revision:
https://patchew.org/QEMU/20260206131438.1857182-1-imammedo@redhat.com/
Igor Mammedov (21):
acpi: add API to build WDAT instructions
x86: q35: add 'wdat' property
x86: q35: generate WDAT ACPI table
tests: acpi: x86/q35: whitelist new WDAT table
tests: acpi: x86/q35: add WDAT table test case
tests: acpi: x86/q35: update expected WDAT blob
arm: sbsa_gwdt: fixup default "clock-frequency"
arm: add tracing events to sbsa_gwdt
arm: virt: create sbsa_gwdt watchdog
arm: sbsa_gwdt: add 'wdat' option
arm: virt: add support for WDAT based watchdog
tests: acpi: arm/virt: whitelist new WDAT table
tests: acpi: arm/virt: add WDAT table test case
tests: acpi: arm/virt: update expected WDAT blob
tests: acpi: arm/virt: whitelist GTDT table
tests: acpi: arm/virt: add GTDT watchdog table test case
tests: acpi: arm/virt: update expected GTDT blob
sbsa_gwdt: reduce code ident
sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition
sbsa_gwdt: reschedule timer on direct WCV load
sbsa_gwdt: limit compare_value to INT64_MAX
include/hw/acpi/wdat-gwdt.h | 19 ++++
include/hw/acpi/wdat-ich9.h | 15 ++++
include/hw/acpi/wdat.h | 118 +++++++++++++++++++++++++
include/hw/i386/pc.h | 1 +
include/hw/watchdog/sbsa_gwdt.h | 1 +
hw/acpi/aml-build.c | 14 +++
hw/acpi/meson.build | 5 +-
hw/acpi/wdat-gwdt-stub.c | 16 ++++
hw/acpi/wdat-gwdt.c | 92 +++++++++++++++++++
hw/acpi/wdat-ich9-stub.c | 15 ++++
hw/acpi/wdat-ich9.c | 90 +++++++++++++++++++
hw/arm/Kconfig | 1 +
hw/arm/virt-acpi-build.c | 65 +++++++++++++-
hw/arm/virt.c | 2 +
hw/core/sysbus-fdt.c | 32 +++++++
hw/i386/acpi-build.c | 12 +++
hw/i386/pc_q35.c | 18 ++++
hw/watchdog/sbsa_gwdt.c | 65 +++++++++-----
hw/watchdog/trace-events | 9 ++
tests/data/acpi/aarch64/virt/GTDT.gwdt | Bin 0 -> 132 bytes
tests/data/acpi/aarch64/virt/WDAT.wdat | Bin 0 -> 260 bytes
tests/data/acpi/x86/q35/WDAT.wdat | Bin 0 -> 308 bytes
tests/qtest/bios-tables-test.c | 54 +++++++++++
23 files changed, 618 insertions(+), 26 deletions(-)
create mode 100644 include/hw/acpi/wdat-gwdt.h
create mode 100644 include/hw/acpi/wdat-ich9.h
create mode 100644 include/hw/acpi/wdat.h
create mode 100644 hw/acpi/wdat-gwdt-stub.c
create mode 100644 hw/acpi/wdat-gwdt.c
create mode 100644 hw/acpi/wdat-ich9-stub.c
create mode 100644 hw/acpi/wdat-ich9.c
create mode 100644 tests/data/acpi/aarch64/virt/GTDT.gwdt
create mode 100644 tests/data/acpi/aarch64/virt/WDAT.wdat
create mode 100644 tests/data/acpi/x86/q35/WDAT.wdat
--
2.47.3
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH v2 01/21] acpi: add API to build WDAT instructions
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-05-13 15:23 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 02/21] x86: q35: add 'wdat' property Igor Mammedov
` (20 subsequent siblings)
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Add definitions for WDAT[1] actions/instructions
and build_append_wdat_ins() API to build table entries.
1)
"Hardware Watchdog Timers Design Specification"
https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
---
include/hw/acpi/wdat.h | 118 +++++++++++++++++++++++++++++++++++++++++
hw/acpi/aml-build.c | 14 +++++
2 files changed, 132 insertions(+)
create mode 100644 include/hw/acpi/wdat.h
diff --git a/include/hw/acpi/wdat.h b/include/hw/acpi/wdat.h
new file mode 100644
index 0000000000..89803eef4b
--- /dev/null
+++ b/include/hw/acpi/wdat.h
@@ -0,0 +1,118 @@
+/*
+ * Watchdog Action Table (WDAT) definitions
+ *
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef QEMU_HW_ACPI_WDAT_H
+#define QEMU_HW_ACPI_WDAT_H
+
+#include "hw/acpi/acpi-defs.h"
+
+/*
+ * Watchdog actions as described in
+ * "Hardware Watchdog Timers Design Specification"
+ * for link to spec see https://uefi.org/acpi
+ * 'Watchdog Action Table (WDAT)'
+ */
+typedef enum {
+ /*
+ * Restarts the watchdog timer's countdown. This action is
+ * required.
+ */
+ WDAT_ACTION_RESET = 0x1,
+ /*
+ * Returns the current countdown value of the watchdog hardware
+ * (in count intervals).
+ */
+ WDAT_ACTION_QUERY_CURRENT_COUNTDOWN_PERIOD = 0x4,
+ /*
+ * Returns the countdown value the watchdog hardware is
+ * configured to use when reset (in count intervals).
+ */
+ WDAT_ACTION_QUERY_COUNTDOWN_PERIOD = 0x5,
+ /*
+ * Sets the countdown value (in count intervals) to be used when
+ * the watchdog timer is reset. This action is required if
+ * WDAT_ACTION_RESET does not explicitly write a new
+ * countdown value to a register during a reset. Otherwise, this
+ * action is optional.
+ */
+ WDAT_ACTION_SET_COUNTDOWN_PERIOD = 0x6,
+ /*
+ * Determines if the watchdog hardware is currently in enabled/
+ * running state. The same result must occur when performed from
+ * both from enabled/stopped state and enabled/running state. If
+ * the watchdog hardware is disabled, results are indeterminate.
+ * This action is required.
+ */
+ WDAT_ACTION_QUERY_RUNNING_STATE = 0x8,
+ /*
+ * Starts the watchdog, if not already in running state. If the
+ * watchdog hardware is disabled, results are indeterminate.
+ * This action is required.
+ */
+ WDAT_ACTION_SET_RUNNING_STATE = 0x9,
+ /*
+ * Determines if the watchdog hardware is currently in enabled/
+ * stopped state. The same result must occur when performed from
+ * both the enabled/stopped state and enabled/running state. If
+ * the watchdog hardware is disabled, results are indeterminate.
+ * This action is required.
+ */
+ WDAT_ACTION_QUERY_STOPPED_STATE = 0xA,
+ /*
+ * Stops the watchdog, if not already in stopped state. If the
+ * watchdog hardware is disabled, results are indeterminate.
+ * This action is required.
+ */
+ WDAT_ACTION_SET_STOPPED_STATE = 0xB,
+ /*
+ * Determines if the watchdog hardware is configured to perform a
+ * reboot when the watchdog is fired.
+ */
+ WDAT_ACTION_QUERY_REBOOT = 0x10,
+ /*
+ * Configures the watchdog hardware to perform a reboot when it
+ * is fired.
+ */
+ WDAT_ACTION_SET_REBOOT = 0x11,
+ /*
+ * Determines if the watchdog hardware is configured to perform a
+ * system shutdown when fired.
+ */
+ WDAT_ACTION_QUERY_SHUTDOWN = 0x12,
+ /*
+ * Configures the watchdog hardware to perform a system shutdown
+ * when fired.
+ */
+ WDAT_ACTION_SET_SHUTDOWN = 0x13,
+ /*
+ * Determines if the current boot was caused by the watchdog
+ * firing. The boot status is required to be set if the watchdog
+ * fired and caused a reboot. It is recommended that the
+ * Watchdog Status be set if the watchdog fired and caused a
+ * shutdown. This action is required.
+ */
+ WDAT_ACTION_QUERY_WATCHDOG_STATUS = 0x20,
+ /*
+ * Sets the watchdog's boot status to the default value. This
+ * action is required.
+ */
+ WDAT_ACTION_SET_WATCHDOG_STATUS = 0x21,
+} WDATAction;
+
+#define WDAT_INS_READ_VALUE 0x0
+#define WDAT_INS_READ_COUNTDOWN 0x1
+#define WDAT_INS_WRITE_VALUE 0x2
+#define WDAT_INS_WRITE_COUNTDOWN 0x3
+#define WDAT_INS_PRESERVE_REGISTER 0x80
+
+void build_append_wdat_ins(GArray *table_data,
+ WDATAction action, uint8_t flags,
+ struct AcpiGenericAddress as,
+ uint32_t val, uint32_t mask);
+
+#endif /* QEMU_HW_ACPI_WDAT_H */
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index ea1c415b21..9f9ce28dcc 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -32,6 +32,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_bridge.h"
#include "qemu/cutils.h"
+#include "hw/acpi/wdat.h"
static GArray *build_alloc_array(void)
{
@@ -2647,3 +2648,16 @@ Aml *aml_error_device(void)
return dev;
}
+
+void build_append_wdat_ins(GArray *table_data,
+ WDATAction action, uint8_t flags,
+ struct AcpiGenericAddress as,
+ uint32_t val, uint32_t mask)
+{
+ build_append_int_noprefix(table_data, action, 1); /* Watchdog Action */
+ build_append_int_noprefix(table_data, flags, 1); /* Instruction Flags */
+ build_append_int_noprefix(table_data, 0, 2); /* Reserved */
+ build_append_gas_from_struct(table_data, &as); /* Register Region */
+ build_append_int_noprefix(table_data, val, 4); /* Value */
+ build_append_int_noprefix(table_data, mask, 4); /* Mask */
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 02/21] x86: q35: add 'wdat' property
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 01/21] acpi: add API to build WDAT instructions Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-05-13 14:58 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 03/21] x86: q35: generate WDAT ACPI table Igor Mammedov
` (19 subsequent siblings)
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Used for enabling WDAT based watchdog for builtin iTCO watchdog.
Usage:
-M q35,wdat={on|off}
By default it is disabled.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
include/hw/i386/pc.h | 1 +
hw/i386/pc_q35.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 1cf88c1697..8e34e57be3 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -45,6 +45,7 @@ typedef struct PCMachineState {
const char *south_bridge;
bool acpi_build_enabled;
+ bool wdat_enabled;
bool smbus_enabled;
bool sata_enabled;
bool hpet_enabled;
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 9158631f76..49f89544f3 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -330,6 +330,18 @@ static void pc_q35_init(MachineState *machine)
}
}
+static bool pc_q35_machine_get_wdat(Object *o, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(o);
+ return pcms->wdat_enabled;
+}
+
+static void pc_q35_machine_set_wdat(Object *o, bool value, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(o);
+ pcms->wdat_enabled = value;
+}
+
#define DEFINE_Q35_MACHINE(major, minor) \
DEFINE_PC_VER_MACHINE(pc_q35, "pc-q35", pc_q35_init, false, NULL, major, minor);
@@ -342,6 +354,7 @@ static void pc_q35_init(MachineState *machine)
static void pc_q35_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ ObjectClass *oc = OBJECT_CLASS(m);
pcmc->pci_root_uid = 0;
pcmc->default_cpu_version = 1;
@@ -360,6 +373,11 @@ static void pc_q35_machine_options(MachineClass *m)
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_UEFI_VARS_X64);
+ object_class_property_add_bool(oc, "wdat",
+ pc_q35_machine_get_wdat, pc_q35_machine_set_wdat);
+ object_class_property_set_description(oc, "wdat",
+ "Enable WDAT watchdog support. Default: off");
+
compat_props_add(m->compat_props,
pc_q35_compat_defaults, pc_q35_compat_defaults_len);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 03/21] x86: q35: generate WDAT ACPI table
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 01/21] acpi: add API to build WDAT instructions Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 02/21] x86: q35: add 'wdat' property Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-05-13 15:47 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table Igor Mammedov
` (18 subsequent siblings)
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
It will generate WDAT table [1] customized for TCO watchdog.
This allows Windows guests (Windows Server 2008/Vista+) to
use TCO watchdog using built-in generic driver, which
alleviates need to install vendor specific drivers.
Given that enabling it might change guest behaviour
(both Windows/Linux) the feature is disabled by default.
Users that need it can enable the feature with
following CLI option.
-machine wdat=on
1)
"Hardware Watchdog Timers Design Specification"
https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
---
include/hw/acpi/wdat-ich9.h | 15 +++++++
hw/acpi/meson.build | 3 +-
hw/acpi/wdat-ich9-stub.c | 15 +++++++
hw/acpi/wdat-ich9.c | 90 +++++++++++++++++++++++++++++++++++++
hw/i386/acpi-build.c | 12 +++++
5 files changed, 134 insertions(+), 1 deletion(-)
create mode 100644 include/hw/acpi/wdat-ich9.h
create mode 100644 hw/acpi/wdat-ich9-stub.c
create mode 100644 hw/acpi/wdat-ich9.c
diff --git a/include/hw/acpi/wdat-ich9.h b/include/hw/acpi/wdat-ich9.h
new file mode 100644
index 0000000000..60a2a6a112
--- /dev/null
+++ b/include/hw/acpi/wdat-ich9.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef QEMU_HW_ACPI_WDAT_ICH9_H
+#define QEMU_HW_ACPI_WDAT_ICH9_H
+
+#include "hw/acpi/aml-build.h"
+
+void build_ich9_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
+ const char *oem_table_id, uint64_t tco_base);
+
+#endif /* QEMU_HW_ACPI_WDAT_ICH9_H */
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index 66c978aae8..22290ca835 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -24,7 +24,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
-acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ich9_timer.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ich9_timer.c', 'wdat-ich9.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
@@ -33,6 +33,7 @@ if have_tpm
endif
system_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
system_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c'))
+system_ss.add(when: 'CONFIG_ACPI_ICH9', if_false: files('wdat-ich9-stub.c'))
system_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
system_ss.add(when: 'CONFIG_GHES_CPER', if_true: files('ghes_cper.c'))
system_ss.add(when: 'CONFIG_GHES_CPER', if_false: files('ghes_cper_stub.c'))
diff --git a/hw/acpi/wdat-ich9-stub.c b/hw/acpi/wdat-ich9-stub.c
new file mode 100644
index 0000000000..7c30ef3558
--- /dev/null
+++ b/hw/acpi/wdat-ich9-stub.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/acpi/wdat-ich9.h"
+
+void build_ich9_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
+ const char *oem_table_id, uint64_t tco_base)
+{
+ g_assert_not_reached();
+}
diff --git a/hw/acpi/wdat-ich9.c b/hw/acpi/wdat-ich9.c
new file mode 100644
index 0000000000..259c45c62d
--- /dev/null
+++ b/hw/acpi/wdat-ich9.c
@@ -0,0 +1,90 @@
+/*
+ * TCO Watchdog Action Table (WDAT)
+ *
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/acpi/wdat.h"
+#include "hw/acpi/wdat-ich9.h"
+#include "hw/southbridge/ich9.h"
+
+#define TCO_REG(base, reg_offset, reg_width) { .space_id = AML_AS_SYSTEM_IO, \
+ .address = base + reg_offset, .bit_width = reg_width, \
+ .access_width = AML_WORD_ACC, };
+
+/*
+ * "Hardware Watchdog Timers Design Specification"
+ * https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
+ *
+ * ICH9 specific implementation.
+ */
+void build_ich9_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
+ const char *oem_table_id, uint64_t tco_base)
+{
+ AcpiTable table = { .sig = "WDAT", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
+ struct AcpiGenericAddress tco_rld = TCO_REG(tco_base, 0x0, 16);
+ struct AcpiGenericAddress tco2_sts = TCO_REG(tco_base, 0x6, 16);
+ struct AcpiGenericAddress tco1_cnt = TCO_REG(tco_base, 0x8, 16);
+ struct AcpiGenericAddress tco_tmr = TCO_REG(tco_base, 0x12, 16);
+
+ acpi_table_begin(&table, table_data);
+ build_append_int_noprefix(table_data, 0x20, 4); /* Watchdog Header Length */
+ build_append_int_noprefix(table_data, 0xff, 2); /* PCI Segment */
+ build_append_int_noprefix(table_data, 0xff, 1); /* PCI Bus Number */
+ build_append_int_noprefix(table_data, 0xff, 1); /* PCI Device Number */
+ build_append_int_noprefix(table_data, 0xff, 1); /* PCI Function Number */
+ build_append_int_noprefix(table_data, 0, 3); /* Reserved */
+ /*
+ * limits/resolution are defined by ICH9 TCO spec
+ */
+ build_append_int_noprefix(table_data, 0x258, 4);/* Timer Period, ms */
+ build_append_int_noprefix(table_data, 0x3ff, 4);/* Maximum Count */
+ build_append_int_noprefix(table_data, 0x4, 4); /* Minimum Count */
+ /*
+ * WATCHDOG_ENABLED & WATCHDOG_STOPPED_IN_SLEEP_STATE
+ */
+ build_append_int_noprefix(table_data, 0x81, 1); /* Watchdog Flags */
+ build_append_int_noprefix(table_data, 0, 3); /* Reserved */
+ /*
+ * watchdog instruction entries
+ */
+ build_append_int_noprefix(table_data, 10 /* # of actions below */, 4);
+ /* Action table */
+ build_append_wdat_ins(table_data, WDAT_ACTION_RESET,
+ WDAT_INS_WRITE_VALUE,
+ tco_rld, 0x1, 0x1ff);
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_RUNNING_STATE,
+ WDAT_INS_READ_VALUE,
+ tco1_cnt, 0x0, 0x800);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_RUNNING_STATE,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ tco1_cnt, 0, 0x800);
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_STOPPED_STATE,
+ WDAT_INS_READ_VALUE,
+ tco1_cnt, 0x800, 0x800);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_STOPPED_STATE,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ tco1_cnt, 0x800, 0x800);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_COUNTDOWN_PERIOD,
+ WDAT_INS_WRITE_COUNTDOWN,
+ tco_tmr, 0x0, 0x3FF);
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_COUNTDOWN_PERIOD,
+ WDAT_INS_READ_COUNTDOWN,
+ tco_tmr, 0x0, 0x3FF);
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_WATCHDOG_STATUS,
+ WDAT_INS_READ_VALUE,
+ tco2_sts, 0x2, 0x2);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_WATCHDOG_STATUS,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ tco2_sts, 0x2, 0x2);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_WATCHDOG_STATUS,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ tco2_sts, 0x4, 0x4);
+
+ acpi_table_end(linker, &table);
+}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index f622b91b76..b623926de4 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -78,6 +78,7 @@
#include "hw/acpi/hmat.h"
#include "hw/acpi/viot.h"
+#include "hw/acpi/wdat-ich9.h"
#include CONFIG_DEVICES
@@ -110,6 +111,7 @@ typedef struct AcpiPmInfo {
uint16_t cpu_hp_io_base;
uint16_t pcihp_io_base;
uint16_t pcihp_io_len;
+ uint64_t tco_io_base;
} AcpiPmInfo;
typedef struct AcpiMiscInfo {
@@ -204,6 +206,7 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
pm->pcihp_io_len = 0;
pm->smi_on_cpuhp = false;
pm->smi_on_cpu_unplug = false;
+ pm->tco_io_base = 0;
assert(obj);
init_common_fadt_data(machine, obj, &pm->fadt);
@@ -225,6 +228,8 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
!!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT));
pm->smi_on_cpu_unplug =
!!(smi_features & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT));
+ pm->tco_io_base = object_property_get_uint(obj, ACPI_PM_PROP_PM_IO_BASE,
+ NULL) + ICH9_PMIO_TCO_RLD;
}
pm->pcihp_io_base =
object_property_get_uint(obj, ACPI_PCIHP_IO_BASE_PROP, NULL);
@@ -2078,6 +2083,13 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id);
+ if (pcms->wdat_enabled == true) {
+ g_assert(pm.tco_io_base);
+ acpi_add_table(table_offsets, tables_blob);
+ build_ich9_wdat(tables_blob, tables->linker, x86ms->oem_id,
+ x86ms->oem_table_id, pm.tco_io_base);
+ }
+
/* Add tables supplied by user (if any) */
for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
unsigned len = acpi_table_len(u);
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (2 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 03/21] x86: q35: generate WDAT ACPI table Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-05-13 15:48 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case Igor Mammedov
` (17 subsequent siblings)
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Acked-by: Ani Sinha <anisinha@redhat.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 +
tests/data/acpi/x86/q35/WDAT.wdat | 0
2 files changed, 1 insertion(+)
create mode 100644 tests/data/acpi/x86/q35/WDAT.wdat
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8b..14b680debe 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,2 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/x86/q35/WDAT.wdat",
diff --git a/tests/data/acpi/x86/q35/WDAT.wdat b/tests/data/acpi/x86/q35/WDAT.wdat
new file mode 100644
index 0000000000..e69de29bb2
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (3 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-05-13 15:49 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob Igor Mammedov
` (16 subsequent siblings)
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
---
tests/qtest/bios-tables-test.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index a5a5b8807b..5b01a657e5 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2530,6 +2530,18 @@ static void test_acpi_isapc_smbios_legacy(void)
free_test_data(&data);
}
+static void test_acpi_q35_wdat(void)
+{
+ test_data data = {
+ .machine = MACHINE_Q35,
+ .arch = "x86",
+ .variant = ".wdat",
+ };
+
+ test_acpi_one("-machine wdat=on", &data);
+ free_test_data(&data);
+}
+
static void test_oem_fields(test_data *data)
{
int i;
@@ -2824,6 +2836,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/cxl", test_acpi_q35_cxl);
#endif
qtest_add_func("acpi/q35/slic", test_acpi_q35_slic);
+ qtest_add_func("acpi/q35/wdat", test_acpi_q35_wdat);
}
if (qtest_has_machine("microvm")) {
qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (4 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-05-13 15:48 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 07/21] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
` (15 subsequent siblings)
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
replace blank table with a new one:
+[000h 0000 4] Signature : "WDAT" [Watchdog Action Table]
+[004h 0004 4] Table Length : 00000134
+[008h 0008 1] Revision : 01
+[009h 0009 1] Checksum : 31
+[00Ah 0010 6] Oem ID : "BOCHS "
+[010h 0016 8] Oem Table ID : "BXPC "
+[018h 0024 4] Oem Revision : 00000001
+[01Ch 0028 4] Asl Compiler ID : "BXPC"
+[020h 0032 4] Asl Compiler Revision : 00000001
+
+[024h 0036 4] Header Length : 00000020
+[028h 0040 2] PCI Segment : 00FF
+[02Ah 0042 1] PCI Bus : FF
+[02Bh 0043 1] PCI Device : FF
+[02Ch 0044 1] PCI Function : FF
+[02Dh 0045 3] Reserved : 000000
+[030h 0048 4] Timer Period : 00000258
+[034h 0052 4] Max Count : 000003FF
+[038h 0056 4] Min Count : 00000004
+[03Ch 0060 1] Flags (decoded below) : 81
+ Enabled : 1
+ Stopped When Asleep : 1
+[03Dh 0061 3] Reserved : 000000
+[040h 0064 4] Watchdog Entry Count : 0000000A
+
+[044h 0068 1] Watchdog Action : 01
+[045h 0069 1] Instruction : 02
+[046h 0070 2] Reserved : 0000
+
+[048h 0072 12] Register Region : [Generic Address Structure]
+[048h 0072 1] Space ID : 01 [SystemIO]
+[049h 0073 1] Bit Width : 10
+[04Ah 0074 1] Bit Offset : 00
+[04Bh 0075 1] Encoded Access Width : 02 [Word Access:16]
+[04Ch 0076 8] Address : 0000000000000660
+
+[054h 0084 4] Value : 00000001
+[058h 0088 4] Register Mask : 000001FF
+
+[05Ch 0092 1] Watchdog Action : 08
+[05Dh 0093 1] Instruction : 00
+[05Eh 0094 2] Reserved : 0000
+
+[060h 0096 12] Register Region : [Generic Address Structure]
+[060h 0096 1] Space ID : 01 [SystemIO]
+[061h 0097 1] Bit Width : 10
+[062h 0098 1] Bit Offset : 00
+[063h 0099 1] Encoded Access Width : 02 [Word Access:16]
+[064h 0100 8] Address : 0000000000000668
+
+[06Ch 0108 4] Value : 00000000
+[070h 0112 4] Register Mask : 00000800
+
+[074h 0116 1] Watchdog Action : 09
+[075h 0117 1] Instruction : 82
+[076h 0118 2] Reserved : 0000
+
+[078h 0120 12] Register Region : [Generic Address Structure]
+[078h 0120 1] Space ID : 01 [SystemIO]
+[079h 0121 1] Bit Width : 10
+[07Ah 0122 1] Bit Offset : 00
+[07Bh 0123 1] Encoded Access Width : 02 [Word Access:16]
+[07Ch 0124 8] Address : 0000000000000668
+
+[084h 0132 4] Value : 00000000
+[088h 0136 4] Register Mask : 00000800
+
+[08Ch 0140 1] Watchdog Action : 0A
+[08Dh 0141 1] Instruction : 00
+[08Eh 0142 2] Reserved : 0000
+
+[090h 0144 12] Register Region : [Generic Address Structure]
+[090h 0144 1] Space ID : 01 [SystemIO]
+[091h 0145 1] Bit Width : 10
+[092h 0146 1] Bit Offset : 00
+[093h 0147 1] Encoded Access Width : 02 [Word Access:16]
+[094h 0148 8] Address : 0000000000000668
+
+[09Ch 0156 4] Value : 00000800
+[0A0h 0160 4] Register Mask : 00000800
+
+[0A4h 0164 1] Watchdog Action : 0B
+[0A5h 0165 1] Instruction : 82
+[0A6h 0166 2] Reserved : 0000
+
+[0A8h 0168 12] Register Region : [Generic Address Structure]
+[0A8h 0168 1] Space ID : 01 [SystemIO]
+[0A9h 0169 1] Bit Width : 10
+[0AAh 0170 1] Bit Offset : 00
+[0ABh 0171 1] Encoded Access Width : 02 [Word Access:16]
+[0ACh 0172 8] Address : 0000000000000668
+
+[0B4h 0180 4] Value : 00000800
+[0B8h 0184 4] Register Mask : 00000800
+
+[0BCh 0188 1] Watchdog Action : 06
+[0BDh 0189 1] Instruction : 03
+[0BEh 0190 2] Reserved : 0000
+
+[0C0h 0192 12] Register Region : [Generic Address Structure]
+[0C0h 0192 1] Space ID : 01 [SystemIO]
+[0C1h 0193 1] Bit Width : 10
+[0C2h 0194 1] Bit Offset : 00
+[0C3h 0195 1] Encoded Access Width : 02 [Word Access:16]
+[0C4h 0196 8] Address : 0000000000000672
+
+[0CCh 0204 4] Value : 00000000
+[0D0h 0208 4] Register Mask : 000003FF
+
+[0D4h 0212 1] Watchdog Action : 05
+[0D5h 0213 1] Instruction : 01
+[0D6h 0214 2] Reserved : 0000
+
+[0D8h 0216 12] Register Region : [Generic Address Structure]
+[0D8h 0216 1] Space ID : 01 [SystemIO]
+[0D9h 0217 1] Bit Width : 10
+[0DAh 0218 1] Bit Offset : 00
+[0DBh 0219 1] Encoded Access Width : 02 [Word Access:16]
+[0DCh 0220 8] Address : 0000000000000672
+
+[0E4h 0228 4] Value : 00000000
+[0E8h 0232 4] Register Mask : 000003FF
+
+[0ECh 0236 1] Watchdog Action : 20
+[0EDh 0237 1] Instruction : 00
+[0EEh 0238 2] Reserved : 0000
+
+[0F0h 0240 12] Register Region : [Generic Address Structure]
+[0F0h 0240 1] Space ID : 01 [SystemIO]
+[0F1h 0241 1] Bit Width : 10
+[0F2h 0242 1] Bit Offset : 00
+[0F3h 0243 1] Encoded Access Width : 02 [Word Access:16]
+[0F4h 0244 8] Address : 0000000000000666
+
+[0FCh 0252 4] Value : 00000002
+[100h 0256 4] Register Mask : 00000002
+
+[104h 0260 1] Watchdog Action : 21
+[105h 0261 1] Instruction : 82
+[106h 0262 2] Reserved : 0000
+
+[108h 0264 12] Register Region : [Generic Address Structure]
+[108h 0264 1] Space ID : 01 [SystemIO]
+[109h 0265 1] Bit Width : 10
+[10Ah 0266 1] Bit Offset : 00
+[10Bh 0267 1] Encoded Access Width : 02 [Word Access:16]
+[10Ch 0268 8] Address : 0000000000000666
+
+[114h 0276 4] Value : 00000002
+[118h 0280 4] Register Mask : 00000002
+
+[11Ch 0284 1] Watchdog Action : 21
+[11Dh 0285 1] Instruction : 82
+[11Eh 0286 2] Reserved : 0000
+
+[120h 0288 12] Register Region : [Generic Address Structure]
+[120h 0288 1] Space ID : 01 [SystemIO]
+[121h 0289 1] Bit Width : 10
+[122h 0290 1] Bit Offset : 00
+[123h 0291 1] Encoded Access Width : 02 [Word Access:16]
+[124h 0292 8] Address : 0000000000000666
+
+[12Ch 0300 4] Value : 00000004
+[130h 0304 4] Register Mask : 00000004
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Acked-by: Ani Sinha <anisinha@redhat.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 -
tests/data/acpi/x86/q35/WDAT.wdat | Bin 0 -> 308 bytes
2 files changed, 1 deletion(-)
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 14b680debe..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,2 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/x86/q35/WDAT.wdat",
diff --git a/tests/data/acpi/x86/q35/WDAT.wdat b/tests/data/acpi/x86/q35/WDAT.wdat
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e1e056b390e51c49f11f7b0d35e4e7c55d8067b1 100644
GIT binary patch
literal 308
zcmaivF$w}f3`JkEx{TV)5#kX9FW|0)oq~c}T8Xtc(2GYhPO+$9AY^#?`OH6WH>b6L
zth#-_J6bm!dNVTt;vLff$K8QJ!5f$W4`2?6f@Jj4QYvm-AjK}Dx5`T;m_2{<;x*QX
lL4w7nzVfzt``kzV@waK@$$at15&T;93Z<9T{~wRc(JwJ97XbhO
literal 0
HcmV?d00001
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 07/21] arm: sbsa_gwdt: fixup default "clock-frequency"
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (5 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 08/21] arm: add tracing events to sbsa_gwdt Igor Mammedov
` (14 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Comment about keeping legacy freq, is wrong to begin with
(should be 62.5MHz), but that value also doesn't make
sense anymore as the watchdog is used only by un-versioned
SBSA board and the later has hard-coded it to 1GHz.
Other potential user (arm/virt) also has system clock at 1GHz.
Drop misleading comment about legacy and set default to 1GHz
to match both boards.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index 7ade5c6f18..b739a3ce3c 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -264,11 +264,10 @@ static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
static const Property wdt_sbsa_gwdt_props[] = {
/*
* Timer frequency in Hz. This must match the frequency used by
- * the CPU's generic timer. Default 62.5Hz matches QEMU's legacy
- * CPU timer frequency default.
+ * the CPU's generic timer.
*/
DEFINE_PROP_UINT64("clock-frequency", struct SBSA_GWDTState, freq,
- 62500000),
+ 1000000000),
};
static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, const void *data)
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 08/21] arm: add tracing events to sbsa_gwdt
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (6 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 07/21] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 09/21] arm: virt: create sbsa_gwdt watchdog Igor Mammedov
` (13 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 8 ++++++++
hw/watchdog/trace-events | 9 +++++++++
2 files changed, 17 insertions(+)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index b739a3ce3c..acb970e8b3 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -24,6 +24,7 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
static const VMStateDescription vmstate_sbsa_gwdt = {
.name = "sbsa-gwdt",
@@ -62,6 +63,7 @@ static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :"
" 0x%x\n", (int)addr);
}
+ trace_sbsa_gwdt_refresh_read(addr, ret);
return ret;
}
@@ -93,6 +95,7 @@ static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size)
qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :"
" 0x%x\n", (int)addr);
}
+ trace_sbsa_gwdt_control_read(addr, ret);
return ret;
}
@@ -127,6 +130,7 @@ static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
unsigned size) {
SBSA_GWDTState *s = SBSA_GWDT(opaque);
+ trace_sbsa_gwdt_refresh_write(offset, data);
if (offset == SBSA_GWDT_WRR) {
s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
@@ -141,6 +145,7 @@ static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size) {
SBSA_GWDTState *s = SBSA_GWDT(opaque);
+ trace_sbsa_gwdt_control_write(offset, data);
switch (offset) {
case SBSA_GWDT_WCS:
s->wcs = data & SBSA_GWDT_WCS_EN;
@@ -180,6 +185,7 @@ static void wdt_sbsa_gwdt_reset(DeviceState *dev)
{
SBSA_GWDTState *s = SBSA_GWDT(dev);
+ trace_sbsa_gwdt_reset();
timer_del(s->timer);
s->wcs = 0;
@@ -196,10 +202,12 @@ static void sbsa_gwdt_timer_sysinterrupt(void *opaque)
if (!(s->wcs & SBSA_GWDT_WCS_WS0)) {
s->wcs |= SBSA_GWDT_WCS_WS0;
+ trace_sbsa_gwdt_ws0_asserted();
sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH);
qemu_set_irq(s->irq, 1);
} else {
s->wcs |= SBSA_GWDT_WCS_WS1;
+ trace_sbsa_gwdt_ws1_asserted();
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
/*
* Reset the watchdog only if the guest gets notified about
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
index ad3be1e9bd..a5c10882f4 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -33,3 +33,12 @@ spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u
# watchdog.c
watchdog_perform_action(unsigned int action) "action=%u"
watchdog_set_action(unsigned int action) "action=%u"
+
+#sbsa_gwdt.c
+sbsa_gwdt_refresh_read(uint64_t addr, uint32_t value) "[0x%" PRIx64 "] -> 0x%" PRIx32
+sbsa_gwdt_refresh_write(uint64_t addr, uint64_t value) "[0x%" PRIx64 "] <- 0x%" PRIx64
+sbsa_gwdt_control_read(uint64_t addr, uint32_t value) "[0x%" PRIx64 "] -> 0x%" PRIx32
+sbsa_gwdt_control_write(uint64_t addr, uint64_t value) "[0x%" PRIx64 "] <- 0x%" PRIx64
+sbsa_gwdt_ws0_asserted(void) "WS0 signal is asserted"
+sbsa_gwdt_ws1_asserted(void) "WS1 signal is asserted"
+sbsa_gwdt_reset(void) "reset watchdog to default state"
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 09/21] arm: virt: create sbsa_gwdt watchdog
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (7 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 08/21] arm: add tracing events to sbsa_gwdt Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 10/21] arm: sbsa_gwdt: add 'wdat' option Igor Mammedov
` (12 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Allow to use SBSA generic watchdog with virt machine type.
(includes conditional generation of corresponding FDT and
ACPI GTDT descriptors)
Use '-device sbsa_gwdt' to command line to enable it.
Tested with Fedora 43:
FDT: -M virt,acpi=off -device sbsa_gwdt
ACPI: -M virt -device sbsa_gwdt
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/arm/Kconfig | 1 +
hw/arm/virt-acpi-build.c | 33 +++++++++++++++++++++++++++++++--
hw/arm/virt.c | 2 ++
hw/core/sysbus-fdt.c | 32 ++++++++++++++++++++++++++++++++
hw/watchdog/sbsa_gwdt.c | 1 +
5 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index c66c452737..1222efadd1 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -36,6 +36,7 @@ config ARM_VIRT
select VIRTIO_MEM_SUPPORTED
select ACPI_CXL
select ACPI_HMAT
+ select WDT_SBSA
config CUBIEBOARD
bool
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 719d2f994e..9c14b1d4d5 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -64,6 +64,7 @@
#include "hw/virtio/virtio-acpi.h"
#include "target/arm/cpu.h"
#include "target/arm/multiprocessing.h"
+#include "hw/watchdog/sbsa_gwdt.h"
#define ARM_SPI_BASE 32
@@ -863,6 +864,8 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
const uint32_t irqflags = 0; /* Interrupt is Level triggered */
AcpiTable table = { .sig = "GTDT", .rev = 3, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
+ uint32_t gtdt_start = table_data->len;
+ Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL);
acpi_table_begin(&table, table_data);
@@ -893,10 +896,15 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, irqflags, 4);
/* CntReadBase Physical address */
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
+
/* Platform Timer Count */
- build_append_int_noprefix(table_data, 0, 4);
+ build_append_int_noprefix(table_data, wdt ? 1 : 0, 4);
/* Platform Timer Offset */
- build_append_int_noprefix(table_data, 0, 4);
+ build_append_int_noprefix(table_data,
+ wdt ? (table_data->len - gtdt_start) +
+ 4 + 4 + 4 /* len of this & following 2 fields to skip */
+ : 0, 4);
+
if (vms->ns_el2_virt_timer_irq) {
/* Virtual EL2 Timer GSIV */
build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL2_VIRT_IRQ, 4);
@@ -906,6 +914,27 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0, 4);
build_append_int_noprefix(table_data, 0, 4);
}
+
+ /* ACPI 6.5 spec: 5.2.25.2 ARM Generic Watchdog Structure (Table 5-124) */
+ if (wdt) {
+ PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
+ SysBusDevice *sd = SYS_BUS_DEVICE(wdt);
+ hwaddr mmio_base = vms->memmap[VIRT_PLATFORM_BUS].base;
+ hwaddr rbase = mmio_base + platform_bus_get_mmio_addr(pbus, sd, 0);
+ hwaddr cbase = mmio_base + platform_bus_get_mmio_addr(pbus, sd, 1);
+ int irq = ARM_SPI_BASE + vms->irqmap[VIRT_PLATFORM_BUS] +
+ platform_bus_get_irqn(pbus, sd, 0);
+
+ build_append_int_noprefix(table_data, 1 /* Type: Watchdog GT */, 1);
+ build_append_int_noprefix(table_data, 28 /* Length */, 2);
+ build_append_int_noprefix(table_data, 0, 1); /* Reserved */
+ /* RefreshFrame Physical Address */
+ build_append_int_noprefix(table_data, rbase, 8);
+ /* WatchdogControlFrame Physical Address */
+ build_append_int_noprefix(table_data, cbase, 8);
+ build_append_int_noprefix(table_data, irq, 4); /* Watchdog Timer GSIV */
+ build_append_int_noprefix(table_data, 0, 4); /* Watchdog Timer Flags */
+ }
acpi_table_end(linker, &table);
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index cab2e21e8a..a87991b591 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -95,6 +95,7 @@
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_host.h"
#include "qemu/guest-random.h"
+#include "hw/watchdog/sbsa_gwdt.h"
static GlobalProperty arm_virt_compat_defaults[] = {
{ TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "48" },
@@ -3474,6 +3475,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_ARM_SMMUV3);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_WDT_SBSA);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c
index 89d0c46445..76aa1bc579 100644
--- a/hw/core/sysbus-fdt.c
+++ b/hw/core/sysbus-fdt.c
@@ -36,6 +36,7 @@
#include "hw/display/ramfb.h"
#include "hw/uefi/var-service-api.h"
#include "hw/arm/fdt.h"
+#include "hw/watchdog/sbsa_gwdt.h"
/*
* internal struct that contains the information to create dynamic
@@ -118,6 +119,36 @@ static int add_uefi_vars_node(SysBusDevice *sbdev, void *opaque)
return 0;
}
+static int add_sbsa_gwdt_node(SysBusDevice *sbdev, void *opaque)
+{
+ PlatformBusFDTData *data = opaque;
+ PlatformBusDevice *pbus = data->pbus;
+ const char *parent_node = data->pbus_node_name;
+ void *fdt = data->fdt;
+ uint64_t cbase, rbase;
+ char *nodename;
+ int irq;
+
+ cbase = platform_bus_get_mmio_addr(pbus, sbdev, 1); /* control frame */
+ rbase = platform_bus_get_mmio_addr(pbus, sbdev, 0); /* refresh frame */
+ irq = platform_bus_get_irqn(pbus, sbdev, 0);
+
+ nodename = g_strdup_printf("%s/watchdog@%" PRIx64, parent_node, cbase);
+ qemu_fdt_add_subnode(fdt, nodename);
+
+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "arm,sbsa-gwdt");
+ qemu_fdt_setprop_cells(fdt, nodename, "reg",
+ cbase, SBSA_GWDT_CMMIO_SIZE,
+ rbase, SBSA_GWDT_RMMIO_SIZE);
+ qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, data->irq_start + irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cell(fdt, nodename, "timeout-sec", 30);
+
+ g_free(nodename);
+ return 0;
+}
+
static int no_fdt_node(SysBusDevice *sbdev, void *opaque)
{
return 0;
@@ -140,6 +171,7 @@ static const BindingEntry bindings[] = {
TYPE_BINDING(TYPE_ARM_SMMUV3, no_fdt_node),
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
+ TYPE_BINDING(TYPE_WDT_SBSA, add_sbsa_gwdt_node),
TYPE_BINDING("", NULL), /* last element */
};
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index acb970e8b3..c4dd8005b7 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -285,6 +285,7 @@ static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, const void *data)
dc->realize = wdt_sbsa_gwdt_realize;
device_class_set_legacy_reset(dc, wdt_sbsa_gwdt_reset);
dc->hotpluggable = false;
+ dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_sbsa_gwdt;
dc->desc = "SBSA-compliant generic watchdog device";
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 10/21] arm: sbsa_gwdt: add 'wdat' option
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (8 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 09/21] arm: virt: create sbsa_gwdt watchdog Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 11/21] arm: virt: add support for WDAT based watchdog Igor Mammedov
` (11 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
it will be used by arm/virt board, to pick WDAT compatible watchdog impl.
and act as switch over to WDAT ACPI table vesus default GTDT ACPI table.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
include/hw/watchdog/sbsa_gwdt.h | 1 +
hw/watchdog/sbsa_gwdt.c | 8 ++++++++
2 files changed, 9 insertions(+)
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
index 307a4f291a..dc77e6be60 100644
--- a/include/hw/watchdog/sbsa_gwdt.h
+++ b/include/hw/watchdog/sbsa_gwdt.h
@@ -73,6 +73,7 @@ typedef struct SBSA_GWDTState {
uint32_t woru;
uint32_t wcvl;
uint32_t wcvu;
+ bool wdat;
} SBSA_GWDTState;
#endif /* WDT_SBSA_GWDT_H */
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index c4dd8005b7..40d80f7f2b 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -265,6 +265,13 @@ static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq);
+ /*
+ * WDAT supports only upto 1KHz resolution,
+ */
+ if (s->wdat) {
+ s->freq = 1000;
+ }
+
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
dev);
}
@@ -276,6 +283,7 @@ static const Property wdt_sbsa_gwdt_props[] = {
*/
DEFINE_PROP_UINT64("clock-frequency", struct SBSA_GWDTState, freq,
1000000000),
+ DEFINE_PROP_BOOL("wdat", struct SBSA_GWDTState, wdat, false),
};
static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, const void *data)
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 11/21] arm: virt: add support for WDAT based watchdog
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (9 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 10/21] arm: sbsa_gwdt: add 'wdat' option Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 12/21] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
` (10 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
And generate WDAT table tailored for sbsa_gwdt and disable
watchdog entry in GTDT ACPI table if WDAT is enabled,
since they are mutualy exclusive due to different
timer resolution of sbsa_gwdt.
To enable use "-device sbsa-gwdt,wdat=on" option
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
include/hw/acpi/wdat-gwdt.h | 19 ++++++++
hw/acpi/meson.build | 2 +
hw/acpi/wdat-gwdt-stub.c | 16 +++++++
hw/acpi/wdat-gwdt.c | 92 +++++++++++++++++++++++++++++++++++++
hw/arm/virt-acpi-build.c | 58 +++++++++++++++++------
5 files changed, 172 insertions(+), 15 deletions(-)
create mode 100644 include/hw/acpi/wdat-gwdt.h
create mode 100644 hw/acpi/wdat-gwdt-stub.c
create mode 100644 hw/acpi/wdat-gwdt.c
diff --git a/include/hw/acpi/wdat-gwdt.h b/include/hw/acpi/wdat-gwdt.h
new file mode 100644
index 0000000000..42339e031e
--- /dev/null
+++ b/include/hw/acpi/wdat-gwdt.h
@@ -0,0 +1,19 @@
+/*
+ * GWDT Watchdog Action Table (WDAT) definition
+ *
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef QEMU_HW_ACPI_WDAT_GWDT_H
+#define QEMU_HW_ACPI_WDAT_GWDT_H
+
+#include "hw/acpi/aml-build.h"
+#include "hw/watchdog/sbsa_gwdt.h"
+
+void build_gwdt_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
+ const char *oem_table_id, uint64_t rbase, uint64_t cbase,
+ uint64_t freq);
+
+#endif /* QEMU_HW_ACPI_WDAT_GWDT_H */
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index 22290ca835..189bbb0257 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -28,12 +28,14 @@ acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ic
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
+acpi_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('wdat-gwdt.c'))
if have_tpm
acpi_ss.add(files('tpm.c'))
endif
system_ss.add(when: 'CONFIG_ACPI', if_false: files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c', 'acpi_interface.c'))
system_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_false: files('pci-bridge-stub.c'))
system_ss.add(when: 'CONFIG_ACPI_ICH9', if_false: files('wdat-ich9-stub.c'))
+system_ss.add(when: 'CONFIG_WDT_SBSA', if_false: files('wdat-gwdt-stub.c'))
system_ss.add_all(when: 'CONFIG_ACPI', if_true: acpi_ss)
system_ss.add(when: 'CONFIG_GHES_CPER', if_true: files('ghes_cper.c'))
system_ss.add(when: 'CONFIG_GHES_CPER', if_false: files('ghes_cper_stub.c'))
diff --git a/hw/acpi/wdat-gwdt-stub.c b/hw/acpi/wdat-gwdt-stub.c
new file mode 100644
index 0000000000..4d43783f70
--- /dev/null
+++ b/hw/acpi/wdat-gwdt-stub.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/acpi/wdat-gwdt.h"
+
+void build_gwdt_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
+ const char *oem_table_id, uint64_t rbase, uint64_t cbase,
+ uint64_t freq)
+{
+ g_assert_not_reached();
+}
diff --git a/hw/acpi/wdat-gwdt.c b/hw/acpi/wdat-gwdt.c
new file mode 100644
index 0000000000..226ba3f01e
--- /dev/null
+++ b/hw/acpi/wdat-gwdt.c
@@ -0,0 +1,92 @@
+/*
+ * SBSA GWDT Watchdog Action Table (WDAT)
+ *
+ * Copyright Red Hat, Inc. 2026
+ * Author(s): Igor Mammedov <imammedo@redhat.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/wdat-gwdt.h"
+#include "hw/acpi/wdat.h"
+#include "hw/watchdog/sbsa_gwdt.h"
+
+#define GWDT_REG(base, reg_offset, reg_width) { \
+ .space_id = AML_AS_SYSTEM_MEMORY, \
+ .address = base + reg_offset, .bit_width = reg_width, \
+ .access_width = AML_DWORD_ACC };
+
+/*
+ * "Hardware Watchdog Timers Design Specification"
+ * https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
+ */
+void build_gwdt_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
+ const char *oem_table_id, uint64_t rbase, uint64_t cbase,
+ uint64_t freq)
+{
+ AcpiTable table = { .sig = "WDAT", .rev = 1, .oem_id = oem_id,
+ .oem_table_id = oem_table_id };
+
+ struct AcpiGenericAddress wrr = GWDT_REG(rbase, 0x0, 32);
+ struct AcpiGenericAddress wor_l = GWDT_REG(cbase, SBSA_GWDT_WOR, 32);
+ struct AcpiGenericAddress wcs = GWDT_REG(cbase, SBSA_GWDT_WCS, 32);
+
+ acpi_table_begin(&table, table_data);
+ build_append_int_noprefix(table_data, 0x20, 4); /* Watchdog Header Length */
+ build_append_int_noprefix(table_data, 0xff, 2); /* PCI Segment */
+ build_append_int_noprefix(table_data, 0xff, 1); /* PCI Bus Number */
+ build_append_int_noprefix(table_data, 0xff, 1); /* PCI Device Number */
+ build_append_int_noprefix(table_data, 0xff, 1); /* PCI Function Number */
+ build_append_int_noprefix(table_data, 0, 3); /* Reserved */
+ /*
+ * WDAT spec suports only 1KHz or more coarse watchdog timer,
+ * Set resolution to minimum supported 1ms.
+ * Before starting watchdog Windows set countdown value to 5min.
+ */
+ g_assert(freq <= 1000);
+ build_append_int_noprefix(table_data, 1, 4);/* Timer Period, ms */
+ /*
+ * Needs to be more than 4min, otherwise Windows 11 won't start watchdog.
+ * Set max to limits to arbitrary max 10min and min to 5sec.
+ */
+ build_append_int_noprefix(table_data, 600 * freq, 4);/* Maximum Count */
+ build_append_int_noprefix(table_data, 5 * freq, 4); /* Minimum Count */
+ /*
+ * WATCHDOG_ENABLED
+ */
+ build_append_int_noprefix(table_data, 0x81, 1); /* Watchdog Flags */
+ build_append_int_noprefix(table_data, 0, 3); /* Reserved */
+ /*
+ * watchdog instruction entries
+ */
+ build_append_int_noprefix(table_data, 8, 4);
+ /* Action table */
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_RUNNING_STATE,
+ WDAT_INS_READ_VALUE,
+ wcs, 0x1, 0x1);
+ build_append_wdat_ins(table_data, WDAT_ACTION_RESET,
+ WDAT_INS_WRITE_VALUE,
+ wrr, 0x1, 0x7);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_COUNTDOWN_PERIOD,
+ WDAT_INS_WRITE_COUNTDOWN,
+ wor_l, 0, 0xffffffff);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_RUNNING_STATE,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ wcs, 1, 0x00000001);
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_STOPPED_STATE,
+ WDAT_INS_READ_VALUE,
+ wcs, 0x0, 0x00000001);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_STOPPED_STATE,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ wcs, 0x0, 0x00000001);
+ build_append_wdat_ins(table_data, WDAT_ACTION_QUERY_WATCHDOG_STATUS,
+ WDAT_INS_READ_VALUE,
+ wcs, 0x4, 0x00000004);
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_WATCHDOG_STATUS,
+ WDAT_INS_WRITE_VALUE | WDAT_INS_PRESERVE_REGISTER,
+ wrr, 0x4, 0x4);
+
+ acpi_table_end(linker, &table);
+}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 9c14b1d4d5..e9670b1a2b 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -65,6 +65,7 @@
#include "target/arm/cpu.h"
#include "target/arm/multiprocessing.h"
#include "hw/watchdog/sbsa_gwdt.h"
+#include "hw/acpi/wdat-gwdt.h"
#define ARM_SPI_BASE 32
@@ -849,12 +850,25 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
acpi_table_end(linker, &table);
}
+static void virt_get_wdt_options(VirtMachineState *vms, Object *wdt,
+ hwaddr *rbase, hwaddr *cbase, int *irq)
+{
+ PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
+ SysBusDevice *sd = SYS_BUS_DEVICE(wdt);
+ hwaddr mmio_base = vms->memmap[VIRT_PLATFORM_BUS].base;
+ *rbase = mmio_base + platform_bus_get_mmio_addr(pbus, sd, 0);
+ *cbase = mmio_base + platform_bus_get_mmio_addr(pbus, sd, 1);
+ *irq = ARM_SPI_BASE + vms->irqmap[VIRT_PLATFORM_BUS] +
+ platform_bus_get_irqn(pbus, sd, 0);
+}
+
/*
* ACPI spec, Revision 6.5
* 5.2.25 Generic Timer Description Table (GTDT)
*/
static void
-build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
+build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms,
+ Object *wdt, bool add_watchdog)
{
/*
* Table 5-117 Flag Definitions
@@ -865,7 +879,6 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
AcpiTable table = { .sig = "GTDT", .rev = 3, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
uint32_t gtdt_start = table_data->len;
- Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL);
acpi_table_begin(&table, table_data);
@@ -898,12 +911,12 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
/* Platform Timer Count */
- build_append_int_noprefix(table_data, wdt ? 1 : 0, 4);
+ build_append_int_noprefix(table_data, add_watchdog ? 1 : 0, 4);
/* Platform Timer Offset */
build_append_int_noprefix(table_data,
- wdt ? (table_data->len - gtdt_start) +
- 4 + 4 + 4 /* len of this & following 2 fields to skip */
- : 0, 4);
+ add_watchdog ? (table_data->len - gtdt_start) +
+ 4 + 4 + 4 /* len of this & following 2 fields to skip */
+ : 0, 4);
if (vms->ns_el2_virt_timer_irq) {
/* Virtual EL2 Timer GSIV */
@@ -916,14 +929,10 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
/* ACPI 6.5 spec: 5.2.25.2 ARM Generic Watchdog Structure (Table 5-124) */
- if (wdt) {
- PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
- SysBusDevice *sd = SYS_BUS_DEVICE(wdt);
- hwaddr mmio_base = vms->memmap[VIRT_PLATFORM_BUS].base;
- hwaddr rbase = mmio_base + platform_bus_get_mmio_addr(pbus, sd, 0);
- hwaddr cbase = mmio_base + platform_bus_get_mmio_addr(pbus, sd, 1);
- int irq = ARM_SPI_BASE + vms->irqmap[VIRT_PLATFORM_BUS] +
- platform_bus_get_irqn(pbus, sd, 0);
+ if (add_watchdog) {
+ int irq;
+ hwaddr rbase, cbase;
+ virt_get_wdt_options(vms, wdt, &rbase, &cbase, &irq);
build_append_int_noprefix(table_data, 1 /* Type: Watchdog GT */, 1);
build_append_int_noprefix(table_data, 28 /* Length */, 2);
@@ -1282,8 +1291,14 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
GArray *table_offsets;
unsigned dsdt, xsdt;
+ bool has_wdat = false;
GArray *tables_blob = tables->table_data;
MachineState *ms = MACHINE(vms);
+ Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL);
+
+ if (wdt) {
+ has_wdat = object_property_get_bool(wdt, "wdat", &error_abort);
+ }
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -1303,6 +1318,19 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
acpi_add_table(table_offsets, tables_blob);
build_madt(tables_blob, tables->linker, vms);
+ acpi_add_table(table_offsets, tables_blob);
+ if (wdt && has_wdat) {
+ int irq;
+ hwaddr rbase, cbase;
+ uint64_t freq = object_property_get_uint(wdt, "clock-frequency",
+ &error_abort);
+ virt_get_wdt_options(vms, wdt, &rbase, &cbase, &irq);
+
+ build_gwdt_wdat(tables_blob, tables->linker,
+ vms->oem_id, vms->oem_table_id,
+ rbase, cbase, freq);
+ }
+
if (!vmc->no_cpu_topology) {
acpi_add_table(table_offsets, tables_blob);
build_pptt(tables_blob, tables->linker, ms,
@@ -1310,7 +1338,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
}
acpi_add_table(table_offsets, tables_blob);
- build_gtdt(tables_blob, tables->linker, vms);
+ build_gtdt(tables_blob, tables->linker, vms, wdt, wdt && !has_wdat);
acpi_add_table(table_offsets, tables_blob);
{
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 12/21] tests: acpi: arm/virt: whitelist new WDAT table
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (10 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 11/21] arm: virt: add support for WDAT based watchdog Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 13/21] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
` (9 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 +
tests/data/acpi/aarch64/virt/WDAT.wdat | 0
2 files changed, 1 insertion(+)
create mode 100644 tests/data/acpi/aarch64/virt/WDAT.wdat
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8b..135186b40b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,2 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/aarch64/virt/WDAT.wdat",
diff --git a/tests/data/acpi/aarch64/virt/WDAT.wdat b/tests/data/acpi/aarch64/virt/WDAT.wdat
new file mode 100644
index 0000000000..e69de29bb2
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 13/21] tests: acpi: arm/virt: add WDAT table test case
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (11 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 12/21] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 14/21] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
` (8 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
tests/qtest/bios-tables-test.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 5b01a657e5..5082866184 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2271,6 +2271,25 @@ static void test_acpi_aarch64_virt_tcg_msi_gicv2m(void)
free_test_data(&data);
}
+static void test_acpi_aarch64_virt_tcg_wdat(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .variant = ".wdat",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 128ULL * MiB,
+ };
+
+ test_acpi_one("-cpu cortex-a57 "
+ "-device sbsa_gwdt,wdat=on", &data);
+ free_test_data(&data);
+}
+
static void test_acpi_q35_viot(void)
{
test_data data = {
@@ -2889,6 +2908,8 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/virt/smmuv3-dev",
test_acpi_aarch64_virt_smmuv3_dev);
}
+ qtest_add_func("acpi/virt/acpi-watchdog",
+ test_acpi_aarch64_virt_tcg_wdat);
}
} else if (strcmp(arch, "riscv64") == 0) {
if (has_tcg && qtest_has_device("virtio-blk-pci")) {
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 14/21] tests: acpi: arm/virt: update expected WDAT blob
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (12 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 13/21] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 15/21] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
` (7 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
replace blank table with a new one:
[000h 0000 004h] Signature : "WDAT" [Watchdog Action Table]
[004h 0004 004h] Table Length : 00000104
[008h 0008 001h] Revision : 01
[009h 0009 001h] Checksum : 3B
[00Ah 0010 006h] Oem ID : "BOCHS "
[010h 0016 008h] Oem Table ID : "BXPC "
[018h 0024 004h] Oem Revision : 00000001
[01Ch 0028 004h] Asl Compiler ID : "BXPC"
[020h 0032 004h] Asl Compiler Revision : 00000001
[024h 0036 004h] Header Length : 00000020
[028h 0040 002h] PCI Segment : 00FF
[02Ah 0042 001h] PCI Bus : FF
[02Bh 0043 001h] PCI Device : FF
[02Ch 0044 001h] PCI Function : FF
[02Dh 0045 003h] Reserved : 000000
[030h 0048 004h] Timer Period : 00000001
[034h 0052 004h] Max Count : 000927C0
[038h 0056 004h] Min Count : 00001388
[03Ch 0060 001h] Flags (decoded below) : 81
Enabled : 1
Stopped When Asleep : 1
[03Dh 0061 003h] Reserved : 000000
[040h 0064 004h] Watchdog Entry Count : 00000008
[044h 0068 001h] Watchdog Action : 08
[045h 0069 001h] Instruction : 00
[046h 0070 002h] Reserved : 0000
[048h 0072 00Ch] Register Region : [Generic Address Structure]
[048h 0072 001h] Space ID : 00 [SystemMemory]
[049h 0073 001h] Bit Width : 20
[04Ah 0074 001h] Bit Offset : 00
[04Bh 0075 001h] Encoded Access Width : 03 [DWord Access:32]
[04Ch 0076 008h] Address : 000000000C001000
[054h 0084 004h] Value : 00000001
[058h 0088 004h] Register Mask : 00000001
[05Ch 0092 001h] Watchdog Action : 01
[05Dh 0093 001h] Instruction : 02
[05Eh 0094 002h] Reserved : 0000
[060h 0096 00Ch] Register Region : [Generic Address Structure]
[060h 0096 001h] Space ID : 00 [SystemMemory]
[061h 0097 001h] Bit Width : 20
[062h 0098 001h] Bit Offset : 00
[063h 0099 001h] Encoded Access Width : 03 [DWord Access:32]
[064h 0100 008h] Address : 000000000C000000
[06Ch 0108 004h] Value : 00000001
[070h 0112 004h] Register Mask : 00000007
[074h 0116 001h] Watchdog Action : 06
[075h 0117 001h] Instruction : 03
[076h 0118 002h] Reserved : 0000
[078h 0120 00Ch] Register Region : [Generic Address Structure]
[078h 0120 001h] Space ID : 00 [SystemMemory]
[079h 0121 001h] Bit Width : 20
[07Ah 0122 001h] Bit Offset : 00
[07Bh 0123 001h] Encoded Access Width : 03 [DWord Access:32]
[07Ch 0124 008h] Address : 000000000C001008
[084h 0132 004h] Value : 00000000
[088h 0136 004h] Register Mask : FFFFFFFF
[08Ch 0140 001h] Watchdog Action : 09
[08Dh 0141 001h] Instruction : 82
[08Eh 0142 002h] Reserved : 0000
[090h 0144 00Ch] Register Region : [Generic Address Structure]
[090h 0144 001h] Space ID : 00 [SystemMemory]
[091h 0145 001h] Bit Width : 20
[092h 0146 001h] Bit Offset : 00
[093h 0147 001h] Encoded Access Width : 03 [DWord Access:32]
[094h 0148 008h] Address : 000000000C001000
[09Ch 0156 004h] Value : 00000001
[0A0h 0160 004h] Register Mask : 00000001
[0A4h 0164 001h] Watchdog Action : 0A
[0A5h 0165 001h] Instruction : 00
[0A6h 0166 002h] Reserved : 0000
[0A8h 0168 00Ch] Register Region : [Generic Address Structure]
[0A8h 0168 001h] Space ID : 00 [SystemMemory]
[0A9h 0169 001h] Bit Width : 20
[0AAh 0170 001h] Bit Offset : 00
[0ABh 0171 001h] Encoded Access Width : 03 [DWord Access:32]
[0ACh 0172 008h] Address : 000000000C001000
[0B4h 0180 004h] Value : 00000000
[0B8h 0184 004h] Register Mask : 00000001
[0BCh 0188 001h] Watchdog Action : 0B
[0BDh 0189 001h] Instruction : 82
[0BEh 0190 002h] Reserved : 0000
[0C0h 0192 00Ch] Register Region : [Generic Address Structure]
[0C0h 0192 001h] Space ID : 00 [SystemMemory]
[0C1h 0193 001h] Bit Width : 20
[0C2h 0194 001h] Bit Offset : 00
[0C3h 0195 001h] Encoded Access Width : 03 [DWord Access:32]
[0C4h 0196 008h] Address : 000000000C001000
[0CCh 0204 004h] Value : 00000000
[0D0h 0208 004h] Register Mask : 00000001
[0D4h 0212 001h] Watchdog Action : 20
[0D5h 0213 001h] Instruction : 00
[0D6h 0214 002h] Reserved : 0000
[0D8h 0216 00Ch] Register Region : [Generic Address Structure]
[0D8h 0216 001h] Space ID : 00 [SystemMemory]
[0D9h 0217 001h] Bit Width : 20
[0DAh 0218 001h] Bit Offset : 00
[0DBh 0219 001h] Encoded Access Width : 03 [DWord Access:32]
[0DCh 0220 008h] Address : 000000000C001000
[0E4h 0228 004h] Value : 00000004
[0E8h 0232 004h] Register Mask : 00000004
[0ECh 0236 001h] Watchdog Action : 21
[0EDh 0237 001h] Instruction : 82
[0EEh 0238 002h] Reserved : 0000
[0F0h 0240 00Ch] Register Region : [Generic Address Structure]
[0F0h 0240 001h] Space ID : 00 [SystemMemory]
[0F1h 0241 001h] Bit Width : 20
[0F2h 0242 001h] Bit Offset : 00
[0F3h 0243 001h] Encoded Access Width : 03 [DWord Access:32]
[0F4h 0244 008h] Address : 000000000C000000
[0FCh 0252 004h] Value : 00000004
[100h 0256 004h] Register Mask : 00000004
Raw Table Data: Length 260 (0x104)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 -
tests/data/acpi/aarch64/virt/WDAT.wdat | Bin 0 -> 260 bytes
2 files changed, 1 deletion(-)
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 135186b40b..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,2 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/WDAT.wdat",
diff --git a/tests/data/acpi/aarch64/virt/WDAT.wdat b/tests/data/acpi/aarch64/virt/WDAT.wdat
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..81786ab0968a5c2004fcf3eee5ec443525c98c3e 100644
GIT binary patch
literal 260
zcmZ9GK?=f93`F1e7j4yr;05B!L%3?|!kvPGUPo6wmN$z`$;Z+_NHV+(^E|hYDnUAR
z*Zy+1?se<U%o3no(*Vca0o~tY!?1@pP)B2Ac5DeoTw09J8UFeTSV}Q+9lXljz4-(`
b^H~d+_^af<nejze-YH+f*oVSLo}&K%0}B)Z
literal 0
HcmV?d00001
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 15/21] tests: acpi: arm/virt: whitelist GTDT table
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (13 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 14/21] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 16/21] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
` (6 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index dfb8523c8b..3e9be28cc4 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1 +1,2 @@
/* List of comma-separated changed AML files to ignore */
+"tests/data/acpi/aarch64/virt/GTDT",
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 16/21] tests: acpi: arm/virt: add GTDT watchdog table test case
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (14 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 15/21] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 17/21] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
` (5 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
tests/qtest/bios-tables-test.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 5082866184..11c6854af8 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2290,6 +2290,24 @@ static void test_acpi_aarch64_virt_tcg_wdat(void)
free_test_data(&data);
}
+static void test_acpi_aarch64_virt_tcg_gtdt_wd(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "aarch64",
+ .variant = ".gwdt",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
+ .ram_start = 0x40000000ULL,
+ .scan_len = 128ULL * MiB,
+ };
+
+ test_acpi_one("-cpu cortex-a57 " "-device sbsa_gwdt", &data);
+ free_test_data(&data);
+}
+
static void test_acpi_q35_viot(void)
{
test_data data = {
@@ -2910,6 +2928,8 @@ int main(int argc, char *argv[])
}
qtest_add_func("acpi/virt/acpi-watchdog",
test_acpi_aarch64_virt_tcg_wdat);
+ qtest_add_func("acpi/virt/gwdt-watchdog",
+ test_acpi_aarch64_virt_tcg_gtdt_wd);
}
} else if (strcmp(arch, "riscv64") == 0) {
if (has_tcg && qtest_has_device("virtio-blk-pci")) {
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 17/21] tests: acpi: arm/virt: update expected GTDT blob
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (15 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 16/21] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 18/21] sbsa_gwdt: reduce code ident Igor Mammedov
` (4 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Expected diff from base GTDT is an addition of watchdog
timer block:
[000h 0000 004h] Signature : "GTDT" [Generic Timer Description Table]
-[004h 0004 004h] Table Length : 00000068
+[004h 0004 004h] Table Length : 00000084
[008h 0008 001h] Revision : 03
-[009h 0009 001h] Checksum : 93
+[009h 0009 001h] Checksum : 39
[00Ah 0010 006h] Oem ID : "BOCHS "
[010h 0016 008h] Oem Table ID : "BXPC "
[018h 0024 004h] Oem Revision : 00000001
@@ -48,17 +48,30 @@
Always On : 0
[050h 0080 008h] Counter Read Block Address : FFFFFFFFFFFFFFFF
-[058h 0088 004h] Platform Timer Count : 00000000
-[05Ch 0092 004h] Platform Timer Offset : 00000000
+[058h 0088 004h] Platform Timer Count : 00000001
+[05Ch 0092 004h] Platform Timer Offset : 00000068
[060h 0096 004h] Virtual EL2 Timer GSIV : 00000000
[064h 0100 004h] Virtual EL2 Timer Flags : 00000000
-Raw Table Data: Length 104 (0x68)
+[068h 0104 001h] Subtable Type : 01 [Generic Watchdog Timer]
+[069h 0105 002h] Length : 001C
+[06Bh 0107 001h] Reserved : 00
+[06Ch 0108 008h] Refresh Frame Address : 000000000C000000
+[074h 0116 008h] Control Frame Address : 000000000C001000
+[07Ch 0124 004h] Timer Interrupt : 00000090
+[080h 0128 004h] Timer Flags (decoded below) : 00000000
+ Trigger Mode : 0
+ Polarity : 0
+ Security : 0
+
+Raw Table Data: Length 132 (0x84)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
tests/qtest/bios-tables-test-allowed-diff.h | 1 -
tests/data/acpi/aarch64/virt/GTDT.gwdt | Bin 0 -> 132 bytes
2 files changed, 1 deletion(-)
create mode 100644 tests/data/acpi/aarch64/virt/GTDT.gwdt
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
index 3e9be28cc4..dfb8523c8b 100644
--- a/tests/qtest/bios-tables-test-allowed-diff.h
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
@@ -1,2 +1 @@
/* List of comma-separated changed AML files to ignore */
-"tests/data/acpi/aarch64/virt/GTDT",
diff --git a/tests/data/acpi/aarch64/virt/GTDT.gwdt b/tests/data/acpi/aarch64/virt/GTDT.gwdt
new file mode 100644
index 0000000000000000000000000000000000000000..e0c2151fa7d3432740bb997d7d33669e30f133aa
GIT binary patch
literal 132
zcmZ<{aS3T*U|?Xjbn<uh2v%^42yj+VP*7lGU|;~TLG*tpU|?WikOdJ83=DD%3=Av`
i3=Gmxz7&*(sRilFfQo?tqYRkh0h0m{dIFfkzyJV@>lgt5
literal 0
HcmV?d00001
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 18/21] sbsa_gwdt: reduce code ident
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (16 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 17/21] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 19/21] sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
` (3 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 38 ++++++++++++++++++++------------------
1 file changed, 20 insertions(+), 18 deletions(-)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index 40d80f7f2b..91f9a4202c 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -105,25 +105,27 @@ static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
timer_del(s->timer);
- if (s->wcs & SBSA_GWDT_WCS_EN) {
- /*
- * Extract the upper 16 bits from woru & 32 bits from worl
- * registers to construct the 48 bit offset value
- */
- timeout = s->woru;
- timeout <<= 32;
- timeout |= s->worl;
- timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, s->freq);
- timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
- (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
- /* store the current timeout value into compare registers */
- s->wcvu = timeout >> 32;
- s->wcvl = timeout;
- }
- timer_mod(s->timer, timeout);
+ if (!(s->wcs & SBSA_GWDT_WCS_EN)) {
+ return;
+ }
+
+ /*
+ * Extract the upper 16 bits from woru & 32 bits from worl
+ * registers to construct the 48 bit offset value
+ */
+ timeout = s->woru;
+ timeout <<= 32;
+ timeout |= s->worl;
+ timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, s->freq);
+ timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
+ (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
+ /* store the current timeout value into compare registers */
+ s->wcvu = timeout >> 32;
+ s->wcvl = timeout;
}
+ timer_mod(s->timer, timeout);
}
static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 19/21] sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (17 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 18/21] sbsa_gwdt: reduce code ident Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 20/21] sbsa_gwdt: reschedule timer on direct WCV load Igor Mammedov
` (2 subsequent siblings)
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
and while at it, simplify timeout calculations
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index 91f9a4202c..c2d6f672f9 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -109,22 +109,20 @@ static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
return;
}
- /*
- * Extract the upper 16 bits from woru & 32 bits from worl
- * registers to construct the 48 bit offset value
- */
- timeout = s->woru;
- timeout <<= 32;
- timeout |= s->worl;
- timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, s->freq);
- timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
(!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
- /* store the current timeout value into compare registers */
+ uint64_t offset = (uint64_t)s->woru << 32 | s->worl;
+ timeout = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ muldiv64(offset, NANOSECONDS_PER_SECOND, s->freq);
+
+ /* store (now + offset)ns in WCV */
s->wcvu = timeout >> 32;
s->wcvl = timeout;
+ } else {
+ g_assert_not_reached();
}
+
+ timeout = (uint64_t)s->wcvu << 32 | s->wcvl;
timer_mod(s->timer, timeout);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 20/21] sbsa_gwdt: reschedule timer on direct WCV load
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (18 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 19/21] sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 21/21] sbsa_gwdt: limit compare_value to INT64_MAX Igor Mammedov
2026-04-28 14:12 ` [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
According to spec[1]
"The compare value can either be loaded directly or indirectly on an
explicit refresh or timeout refresh"
while QEMU does allow to write WCV, it doesn't act on
new value, which it should do according to pseudo code in spec:
"TimeoutRefresh = ( SystemCounter [63:0] > CompareValue [63:0])"
fix it by updating timer on WCV write.
Fixes Windows watchdog reboots, since it sets
WOR to ~4sec && never triggers WRR refresh
it however writes insane lage value into WCV
right after WOR & WCS enable, which effectively
cancels too small WOR value and missing WRR.
1) Arm® Server Base System Architecture 6.0
Platform Design Document
DEN0029D 6.0
"A.2 Watchdog Operation"
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index c2d6f672f9..7fec61b7b0 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -44,6 +44,7 @@ static const VMStateDescription vmstate_sbsa_gwdt = {
typedef enum WdtRefreshType {
EXPLICIT_REFRESH = 0,
TIMEOUT_REFRESH = 1,
+ WCV_LOAD = 2,
} WdtRefreshType;
static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
@@ -118,8 +119,6 @@ static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
/* store (now + offset)ns in WCV */
s->wcvu = timeout >> 32;
s->wcvl = timeout;
- } else {
- g_assert_not_reached();
}
timeout = (uint64_t)s->wcvu << 32 | s->wcvl;
@@ -169,10 +168,16 @@ static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
case SBSA_GWDT_WCV:
s->wcvl = data;
+ if (s->wcs & SBSA_GWDT_WCS_EN) {
+ sbsa_gwdt_update_timer(s, WCV_LOAD);
+ }
break;
case SBSA_GWDT_WCVU:
s->wcvu = data;
+ if (s->wcs & SBSA_GWDT_WCS_EN) {
+ sbsa_gwdt_update_timer(s, WCV_LOAD);
+ }
break;
default:
--
2.47.3
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH v2 21/21] sbsa_gwdt: limit compare_value to INT64_MAX
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (19 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 20/21] sbsa_gwdt: reschedule timer on direct WCV load Igor Mammedov
@ 2026-03-03 9:25 ` Igor Mammedov
2026-04-28 14:12 ` [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
21 siblings, 0 replies; 33+ messages in thread
From: Igor Mammedov @ 2026-03-03 9:25 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
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 <imammedo@redhat.com>
---
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
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
` (20 preceding siblings ...)
2026-03-03 9:25 ` [PATCH v2 21/21] sbsa_gwdt: limit compare_value to INT64_MAX Igor Mammedov
@ 2026-04-28 14:12 ` Igor Mammedov
2026-05-12 13:30 ` Igor Mammedov
21 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-04-28 14:12 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
On Tue, 3 Mar 2026 10:25:11 +0100
Igor Mammedov <imammedo@redhat.com> wrote:
> Changelog:
> v2:
> * ditch generic '-machine acpi-watchdog' option in favor of
> board specific variants:
> x86/q35: -machine wdat={on|off}
> arm/virt: -device sbsa_gwdt,wdat={on|off}
> * arm/virt: add FDT and GTDT ACPI entries for GWDT when it's present
> and hide GDTD one when WDAT is enabled.
> * arm/virt: add test case for GTDT
> * [18-21] optional GWDT cleanup/fixes in handling WCV register update,
> make QEMU behave according to spec (at least the way I read it and
> it appears MS also read it that way). It fixes Windows 11 reboots when
> GWDT is present (without WDAT). With that fixed it's up to MS to fix
> their driver to set sane timeout as with the current one wdatchdog
> will never trigger.
given merge window should be open by now,
gentle ping
> Windows doesn't ship built-in TCO watchdog driver, and users are
> forced to install vendor specific driver(s) if such exists.
> However the OS provides a generic watchdog driver that uses
> ACPI WDAT table [1] to abstract actual hardware behind it.
> The same applies to ARM version of Windows.
>
> This series adds
> * WDAT table tailored for TCO watchdog that Q35 already
> has as part of ICH9 chipset and a knob to enable it.
> * SBSA GWDT to arm/virt machine with WDAT table tailored
> for it and necessary tweaks to GWDT to make usable
> with WDAT driver.
> * in addition to WDAT, it also adds native variant
> with GWDT described in FDT and DTDT
> (broken on Windows/works on linux).
>
> Guest OS WDAT support is present since Windows Vista and Linux since 2016[2].
>
> One can test it launching VM with following options:
> * x86:
> -machine q35,wdat=on
> * arm/virt:
> -device sbsa_gwdt,wdat=on
>
> to trace access to TCO registers one can add to CLI:
> -trace "tco_*"
> to trace access to GWDT registers one can add to CLI:
> -trace "sbsa_gwdt*"
>
> To verify that guest uses WDAT (both Windows and Linux would use it if present),
> * on linux make sure that watchdog service is configured/enabled
> (use wdctl to check what watchdog device is in use) and then
> trigger kernel panic with command:
> echo c > /proc/sysrq-trigger
> * on Windows kill svchost process, running cmd in admin mode:
> taskkill /f /im svchost.exe
>
> Tested with WS2025 & RHEL9.6 & Fedora 43 (aarch64)
>
> git tree at: https://gitlab.com/imammedo/qemu/-/commits/gwdt_v2
>
> 1) http://msdn.microsoft.com/en-us/windows/hardware/gg463320.aspx
> 2) https://lwn.net/Articles/700524/
>
> PS:
> previous revision:
> https://patchew.org/QEMU/20260206131438.1857182-1-imammedo@redhat.com/
>
> Igor Mammedov (21):
> acpi: add API to build WDAT instructions
> x86: q35: add 'wdat' property
> x86: q35: generate WDAT ACPI table
> tests: acpi: x86/q35: whitelist new WDAT table
> tests: acpi: x86/q35: add WDAT table test case
> tests: acpi: x86/q35: update expected WDAT blob
> arm: sbsa_gwdt: fixup default "clock-frequency"
> arm: add tracing events to sbsa_gwdt
> arm: virt: create sbsa_gwdt watchdog
> arm: sbsa_gwdt: add 'wdat' option
> arm: virt: add support for WDAT based watchdog
> tests: acpi: arm/virt: whitelist new WDAT table
> tests: acpi: arm/virt: add WDAT table test case
> tests: acpi: arm/virt: update expected WDAT blob
> tests: acpi: arm/virt: whitelist GTDT table
> tests: acpi: arm/virt: add GTDT watchdog table test case
> tests: acpi: arm/virt: update expected GTDT blob
> sbsa_gwdt: reduce code ident
> sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition
> sbsa_gwdt: reschedule timer on direct WCV load
> sbsa_gwdt: limit compare_value to INT64_MAX
>
> include/hw/acpi/wdat-gwdt.h | 19 ++++
> include/hw/acpi/wdat-ich9.h | 15 ++++
> include/hw/acpi/wdat.h | 118 +++++++++++++++++++++++++
> include/hw/i386/pc.h | 1 +
> include/hw/watchdog/sbsa_gwdt.h | 1 +
> hw/acpi/aml-build.c | 14 +++
> hw/acpi/meson.build | 5 +-
> hw/acpi/wdat-gwdt-stub.c | 16 ++++
> hw/acpi/wdat-gwdt.c | 92 +++++++++++++++++++
> hw/acpi/wdat-ich9-stub.c | 15 ++++
> hw/acpi/wdat-ich9.c | 90 +++++++++++++++++++
> hw/arm/Kconfig | 1 +
> hw/arm/virt-acpi-build.c | 65 +++++++++++++-
> hw/arm/virt.c | 2 +
> hw/core/sysbus-fdt.c | 32 +++++++
> hw/i386/acpi-build.c | 12 +++
> hw/i386/pc_q35.c | 18 ++++
> hw/watchdog/sbsa_gwdt.c | 65 +++++++++-----
> hw/watchdog/trace-events | 9 ++
> tests/data/acpi/aarch64/virt/GTDT.gwdt | Bin 0 -> 132 bytes
> tests/data/acpi/aarch64/virt/WDAT.wdat | Bin 0 -> 260 bytes
> tests/data/acpi/x86/q35/WDAT.wdat | Bin 0 -> 308 bytes
> tests/qtest/bios-tables-test.c | 54 +++++++++++
> 23 files changed, 618 insertions(+), 26 deletions(-)
> create mode 100644 include/hw/acpi/wdat-gwdt.h
> create mode 100644 include/hw/acpi/wdat-ich9.h
> create mode 100644 include/hw/acpi/wdat.h
> create mode 100644 hw/acpi/wdat-gwdt-stub.c
> create mode 100644 hw/acpi/wdat-gwdt.c
> create mode 100644 hw/acpi/wdat-ich9-stub.c
> create mode 100644 hw/acpi/wdat-ich9.c
> create mode 100644 tests/data/acpi/aarch64/virt/GTDT.gwdt
> create mode 100644 tests/data/acpi/aarch64/virt/WDAT.wdat
> create mode 100644 tests/data/acpi/x86/q35/WDAT.wdat
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards
2026-04-28 14:12 ` [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
@ 2026-05-12 13:30 ` Igor Mammedov
2026-05-12 14:45 ` Ani Sinha
0 siblings, 1 reply; 33+ messages in thread
From: Igor Mammedov @ 2026-05-12 13:30 UTC (permalink / raw)
To: qemu-devel
Cc: mst, anisinha, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
On Tue, 28 Apr 2026 16:12:15 +0200
Igor Mammedov <imammedo@redhat.com> wrote:
> On Tue, 3 Mar 2026 10:25:11 +0100
> Igor Mammedov <imammedo@redhat.com> wrote:
>
> > Changelog:
> > v2:
> > * ditch generic '-machine acpi-watchdog' option in favor of
> > board specific variants:
> > x86/q35: -machine wdat={on|off}
> > arm/virt: -device sbsa_gwdt,wdat={on|off}
> > * arm/virt: add FDT and GTDT ACPI entries for GWDT when it's present
> > and hide GDTD one when WDAT is enabled.
> > * arm/virt: add test case for GTDT
> > * [18-21] optional GWDT cleanup/fixes in handling WCV register update,
> > make QEMU behave according to spec (at least the way I read it and
> > it appears MS also read it that way). It fixes Windows 11 reboots when
> > GWDT is present (without WDAT). With that fixed it's up to MS to fix
> > their driver to set sane timeout as with the current one wdatchdog
> > will never trigger.
>
> given merge window should be open by now,
> gentle ping
2 weeks later,
yet another ping
>
> > Windows doesn't ship built-in TCO watchdog driver, and users are
> > forced to install vendor specific driver(s) if such exists.
> > However the OS provides a generic watchdog driver that uses
> > ACPI WDAT table [1] to abstract actual hardware behind it.
> > The same applies to ARM version of Windows.
> >
> > This series adds
> > * WDAT table tailored for TCO watchdog that Q35 already
> > has as part of ICH9 chipset and a knob to enable it.
> > * SBSA GWDT to arm/virt machine with WDAT table tailored
> > for it and necessary tweaks to GWDT to make usable
> > with WDAT driver.
> > * in addition to WDAT, it also adds native variant
> > with GWDT described in FDT and DTDT
> > (broken on Windows/works on linux).
> >
> > Guest OS WDAT support is present since Windows Vista and Linux since 2016[2].
> >
> > One can test it launching VM with following options:
> > * x86:
> > -machine q35,wdat=on
> > * arm/virt:
> > -device sbsa_gwdt,wdat=on
> >
> > to trace access to TCO registers one can add to CLI:
> > -trace "tco_*"
> > to trace access to GWDT registers one can add to CLI:
> > -trace "sbsa_gwdt*"
> >
> > To verify that guest uses WDAT (both Windows and Linux would use it if present),
> > * on linux make sure that watchdog service is configured/enabled
> > (use wdctl to check what watchdog device is in use) and then
> > trigger kernel panic with command:
> > echo c > /proc/sysrq-trigger
> > * on Windows kill svchost process, running cmd in admin mode:
> > taskkill /f /im svchost.exe
> >
> > Tested with WS2025 & RHEL9.6 & Fedora 43 (aarch64)
> >
> > git tree at: https://gitlab.com/imammedo/qemu/-/commits/gwdt_v2
> >
> > 1) http://msdn.microsoft.com/en-us/windows/hardware/gg463320.aspx
> > 2) https://lwn.net/Articles/700524/
> >
> > PS:
> > previous revision:
> > https://patchew.org/QEMU/20260206131438.1857182-1-imammedo@redhat.com/
> >
> > Igor Mammedov (21):
> > acpi: add API to build WDAT instructions
> > x86: q35: add 'wdat' property
> > x86: q35: generate WDAT ACPI table
> > tests: acpi: x86/q35: whitelist new WDAT table
> > tests: acpi: x86/q35: add WDAT table test case
> > tests: acpi: x86/q35: update expected WDAT blob
> > arm: sbsa_gwdt: fixup default "clock-frequency"
> > arm: add tracing events to sbsa_gwdt
> > arm: virt: create sbsa_gwdt watchdog
> > arm: sbsa_gwdt: add 'wdat' option
> > arm: virt: add support for WDAT based watchdog
> > tests: acpi: arm/virt: whitelist new WDAT table
> > tests: acpi: arm/virt: add WDAT table test case
> > tests: acpi: arm/virt: update expected WDAT blob
> > tests: acpi: arm/virt: whitelist GTDT table
> > tests: acpi: arm/virt: add GTDT watchdog table test case
> > tests: acpi: arm/virt: update expected GTDT blob
> > sbsa_gwdt: reduce code ident
> > sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition
> > sbsa_gwdt: reschedule timer on direct WCV load
> > sbsa_gwdt: limit compare_value to INT64_MAX
> >
> > include/hw/acpi/wdat-gwdt.h | 19 ++++
> > include/hw/acpi/wdat-ich9.h | 15 ++++
> > include/hw/acpi/wdat.h | 118 +++++++++++++++++++++++++
> > include/hw/i386/pc.h | 1 +
> > include/hw/watchdog/sbsa_gwdt.h | 1 +
> > hw/acpi/aml-build.c | 14 +++
> > hw/acpi/meson.build | 5 +-
> > hw/acpi/wdat-gwdt-stub.c | 16 ++++
> > hw/acpi/wdat-gwdt.c | 92 +++++++++++++++++++
> > hw/acpi/wdat-ich9-stub.c | 15 ++++
> > hw/acpi/wdat-ich9.c | 90 +++++++++++++++++++
> > hw/arm/Kconfig | 1 +
> > hw/arm/virt-acpi-build.c | 65 +++++++++++++-
> > hw/arm/virt.c | 2 +
> > hw/core/sysbus-fdt.c | 32 +++++++
> > hw/i386/acpi-build.c | 12 +++
> > hw/i386/pc_q35.c | 18 ++++
> > hw/watchdog/sbsa_gwdt.c | 65 +++++++++-----
> > hw/watchdog/trace-events | 9 ++
> > tests/data/acpi/aarch64/virt/GTDT.gwdt | Bin 0 -> 132 bytes
> > tests/data/acpi/aarch64/virt/WDAT.wdat | Bin 0 -> 260 bytes
> > tests/data/acpi/x86/q35/WDAT.wdat | Bin 0 -> 308 bytes
> > tests/qtest/bios-tables-test.c | 54 +++++++++++
> > 23 files changed, 618 insertions(+), 26 deletions(-)
> > create mode 100644 include/hw/acpi/wdat-gwdt.h
> > create mode 100644 include/hw/acpi/wdat-ich9.h
> > create mode 100644 include/hw/acpi/wdat.h
> > create mode 100644 hw/acpi/wdat-gwdt-stub.c
> > create mode 100644 hw/acpi/wdat-gwdt.c
> > create mode 100644 hw/acpi/wdat-ich9-stub.c
> > create mode 100644 hw/acpi/wdat-ich9.c
> > create mode 100644 tests/data/acpi/aarch64/virt/GTDT.gwdt
> > create mode 100644 tests/data/acpi/aarch64/virt/WDAT.wdat
> > create mode 100644 tests/data/acpi/x86/q35/WDAT.wdat
> >
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards
2026-05-12 13:30 ` Igor Mammedov
@ 2026-05-12 14:45 ` Ani Sinha
0 siblings, 0 replies; 33+ messages in thread
From: Ani Sinha @ 2026-05-12 14:45 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, pbonzini, peter.maydell, shannon.zhaosl, philmd,
zhao1.liu, rad, leif.lindholm, qemu-arm
> On 12 May 2026, at 7:00 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>
> On Tue, 28 Apr 2026 16:12:15 +0200
> Igor Mammedov <imammedo@redhat.com> wrote:
>
>> On Tue, 3 Mar 2026 10:25:11 +0100
>> Igor Mammedov <imammedo@redhat.com> wrote:
>>
>>> Changelog:
>>> v2:
>>> * ditch generic '-machine acpi-watchdog' option in favor of
>>> board specific variants:
>>> x86/q35: -machine wdat={on|off}
>>> arm/virt: -device sbsa_gwdt,wdat={on|off}
>>> * arm/virt: add FDT and GTDT ACPI entries for GWDT when it's present
>>> and hide GDTD one when WDAT is enabled.
>>> * arm/virt: add test case for GTDT
>>> * [18-21] optional GWDT cleanup/fixes in handling WCV register update,
>>> make QEMU behave according to spec (at least the way I read it and
>>> it appears MS also read it that way). It fixes Windows 11 reboots when
>>> GWDT is present (without WDAT). With that fixed it's up to MS to fix
>>> their driver to set sane timeout as with the current one wdatchdog
>>> will never trigger.
>>
>> given merge window should be open by now,
>> gentle ping
>
> 2 weeks later,
> yet another ping
I have this in my queue for review.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 02/21] x86: q35: add 'wdat' property
2026-03-03 9:25 ` [PATCH v2 02/21] x86: q35: add 'wdat' property Igor Mammedov
@ 2026-05-13 14:58 ` Zhao Liu
2026-05-14 7:16 ` Ani Sinha
0 siblings, 1 reply; 33+ messages in thread
From: Zhao Liu @ 2026-05-13 14:58 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Tue, Mar 03, 2026 at 10:25:13AM +0100, Igor Mammedov wrote:
> Date: Tue, 3 Mar 2026 10:25:13 +0100
> From: Igor Mammedov <imammedo@redhat.com>
> Subject: [PATCH v2 02/21] x86: q35: add 'wdat' property
>
> Used for enabling WDAT based watchdog for builtin iTCO watchdog.
> Usage:
> -M q35,wdat={on|off}
> By default it is disabled.
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> include/hw/i386/pc.h | 1 +
> hw/i386/pc_q35.c | 18 ++++++++++++++++++
> 2 files changed, 19 insertions(+)
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 01/21] acpi: add API to build WDAT instructions
2026-03-03 9:25 ` [PATCH v2 01/21] acpi: add API to build WDAT instructions Igor Mammedov
@ 2026-05-13 15:23 ` Zhao Liu
0 siblings, 0 replies; 33+ messages in thread
From: Zhao Liu @ 2026-05-13 15:23 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Tue, Mar 03, 2026 at 10:25:12AM +0100, Igor Mammedov wrote:
> Date: Tue, 3 Mar 2026 10:25:12 +0100
> From: Igor Mammedov <imammedo@redhat.com>
> Subject: [PATCH v2 01/21] acpi: add API to build WDAT instructions
>
> Add definitions for WDAT[1] actions/instructions
> and build_append_wdat_ins() API to build table entries.
>
> 1)
> "Hardware Watchdog Timers Design Specification"
> https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Reviewed-by: Ani Sinha <anisinha@redhat.com>
> ---
> include/hw/acpi/wdat.h | 118 +++++++++++++++++++++++++++++++++++++++++
> hw/acpi/aml-build.c | 14 +++++
> 2 files changed, 132 insertions(+)
> create mode 100644 include/hw/acpi/wdat.h
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 03/21] x86: q35: generate WDAT ACPI table
2026-05-13 15:47 ` Zhao Liu
@ 2026-05-13 15:28 ` Michael S. Tsirkin
0 siblings, 0 replies; 33+ messages in thread
From: Michael S. Tsirkin @ 2026-05-13 15:28 UTC (permalink / raw)
To: Zhao Liu
Cc: Igor Mammedov, qemu-devel, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Wed, May 13, 2026 at 11:47:19PM +0800, Zhao Liu wrote:
> On Tue, Mar 03, 2026 at 10:25:14AM +0100, Igor Mammedov wrote:
> > Date: Tue, 3 Mar 2026 10:25:14 +0100
> > From: Igor Mammedov <imammedo@redhat.com>
> > Subject: [PATCH v2 03/21] x86: q35: generate WDAT ACPI table
> >
> > It will generate WDAT table [1] customized for TCO watchdog.
> > This allows Windows guests (Windows Server 2008/Vista+) to
> > use TCO watchdog using built-in generic driver, which
> > alleviates need to install vendor specific drivers.
> >
> > Given that enabling it might change guest behaviour
> > (both Windows/Linux) the feature is disabled by default.
> >
> > Users that need it can enable the feature with
> > following CLI option.
> > -machine wdat=on
> >
> > 1)
> > "Hardware Watchdog Timers Design Specification"
> > https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
> >
> > Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> > Reviewed-by: Ani Sinha <anisinha@redhat.com>
> > ---
> > include/hw/acpi/wdat-ich9.h | 15 +++++++
> > hw/acpi/meson.build | 3 +-
> > hw/acpi/wdat-ich9-stub.c | 15 +++++++
> > hw/acpi/wdat-ich9.c | 90 +++++++++++++++++++++++++++++++++++++
> > hw/i386/acpi-build.c | 12 +++++
> > 5 files changed, 134 insertions(+), 1 deletion(-)
> > create mode 100644 include/hw/acpi/wdat-ich9.h
> > create mode 100644 hw/acpi/wdat-ich9-stub.c
> > create mode 100644 hw/acpi/wdat-ich9.c
>
> ...
>
> > +void build_ich9_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
> > + const char *oem_table_id, uint64_t tco_base)
> > +{
> > + AcpiTable table = { .sig = "WDAT", .rev = 1, .oem_id = oem_id,
> > + .oem_table_id = oem_table_id };
> > + struct AcpiGenericAddress tco_rld = TCO_REG(tco_base, 0x0, 16);
> > + struct AcpiGenericAddress tco2_sts = TCO_REG(tco_base, 0x6, 16);
> > + struct AcpiGenericAddress tco1_cnt = TCO_REG(tco_base, 0x8, 16);
> > + struct AcpiGenericAddress tco_tmr = TCO_REG(tco_base, 0x12, 16);
> > +
> > + acpi_table_begin(&table, table_data);
> > + build_append_int_noprefix(table_data, 0x20, 4); /* Watchdog Header Length */
> > + build_append_int_noprefix(table_data, 0xff, 2); /* PCI Segment */
> > + build_append_int_noprefix(table_data, 0xff, 1); /* PCI Bus Number */
> > + build_append_int_noprefix(table_data, 0xff, 1); /* PCI Device Number */
> > + build_append_int_noprefix(table_data, 0xff, 1); /* PCI Function Number */
> > + build_append_int_noprefix(table_data, 0, 3); /* Reserved */
> > + /*
> > + * limits/resolution are defined by ICH9 TCO spec
> > + */
> > + build_append_int_noprefix(table_data, 0x258, 4);/* Timer Period, ms */
> > + build_append_int_noprefix(table_data, 0x3ff, 4);/* Maximum Count */
> > + build_append_int_noprefix(table_data, 0x4, 4); /* Minimum Count */
>
> Spec said: The time-out period before the WDT fires is recommended to be at
> least 5 minutes and is required to be less than 4,294,967,296 count
> intervals.
>
> Here we encode 0x4 * 0x258 = 2400ms, less than 5 minutes. But I
> understand because "5 minutes" is just "recommanded" by spec, so 2400ms is
> okay.
>
> LGTM,
>
> Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
maybe a comment why it's shorter?
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 03/21] x86: q35: generate WDAT ACPI table
2026-03-03 9:25 ` [PATCH v2 03/21] x86: q35: generate WDAT ACPI table Igor Mammedov
@ 2026-05-13 15:47 ` Zhao Liu
2026-05-13 15:28 ` Michael S. Tsirkin
0 siblings, 1 reply; 33+ messages in thread
From: Zhao Liu @ 2026-05-13 15:47 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Tue, Mar 03, 2026 at 10:25:14AM +0100, Igor Mammedov wrote:
> Date: Tue, 3 Mar 2026 10:25:14 +0100
> From: Igor Mammedov <imammedo@redhat.com>
> Subject: [PATCH v2 03/21] x86: q35: generate WDAT ACPI table
>
> It will generate WDAT table [1] customized for TCO watchdog.
> This allows Windows guests (Windows Server 2008/Vista+) to
> use TCO watchdog using built-in generic driver, which
> alleviates need to install vendor specific drivers.
>
> Given that enabling it might change guest behaviour
> (both Windows/Linux) the feature is disabled by default.
>
> Users that need it can enable the feature with
> following CLI option.
> -machine wdat=on
>
> 1)
> "Hardware Watchdog Timers Design Specification"
> https://uefi.org/acpi 'Watchdog Action Table (WDAT)'
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Reviewed-by: Ani Sinha <anisinha@redhat.com>
> ---
> include/hw/acpi/wdat-ich9.h | 15 +++++++
> hw/acpi/meson.build | 3 +-
> hw/acpi/wdat-ich9-stub.c | 15 +++++++
> hw/acpi/wdat-ich9.c | 90 +++++++++++++++++++++++++++++++++++++
> hw/i386/acpi-build.c | 12 +++++
> 5 files changed, 134 insertions(+), 1 deletion(-)
> create mode 100644 include/hw/acpi/wdat-ich9.h
> create mode 100644 hw/acpi/wdat-ich9-stub.c
> create mode 100644 hw/acpi/wdat-ich9.c
...
> +void build_ich9_wdat(GArray *table_data, BIOSLinker *linker, const char *oem_id,
> + const char *oem_table_id, uint64_t tco_base)
> +{
> + AcpiTable table = { .sig = "WDAT", .rev = 1, .oem_id = oem_id,
> + .oem_table_id = oem_table_id };
> + struct AcpiGenericAddress tco_rld = TCO_REG(tco_base, 0x0, 16);
> + struct AcpiGenericAddress tco2_sts = TCO_REG(tco_base, 0x6, 16);
> + struct AcpiGenericAddress tco1_cnt = TCO_REG(tco_base, 0x8, 16);
> + struct AcpiGenericAddress tco_tmr = TCO_REG(tco_base, 0x12, 16);
> +
> + acpi_table_begin(&table, table_data);
> + build_append_int_noprefix(table_data, 0x20, 4); /* Watchdog Header Length */
> + build_append_int_noprefix(table_data, 0xff, 2); /* PCI Segment */
> + build_append_int_noprefix(table_data, 0xff, 1); /* PCI Bus Number */
> + build_append_int_noprefix(table_data, 0xff, 1); /* PCI Device Number */
> + build_append_int_noprefix(table_data, 0xff, 1); /* PCI Function Number */
> + build_append_int_noprefix(table_data, 0, 3); /* Reserved */
> + /*
> + * limits/resolution are defined by ICH9 TCO spec
> + */
> + build_append_int_noprefix(table_data, 0x258, 4);/* Timer Period, ms */
> + build_append_int_noprefix(table_data, 0x3ff, 4);/* Maximum Count */
> + build_append_int_noprefix(table_data, 0x4, 4); /* Minimum Count */
Spec said: The time-out period before the WDT fires is recommended to be at
least 5 minutes and is required to be less than 4,294,967,296 count
intervals.
Here we encode 0x4 * 0x258 = 2400ms, less than 5 minutes. But I
understand because "5 minutes" is just "recommanded" by spec, so 2400ms is
okay.
LGTM,
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob
2026-03-03 9:25 ` [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob Igor Mammedov
@ 2026-05-13 15:48 ` Zhao Liu
0 siblings, 0 replies; 33+ messages in thread
From: Zhao Liu @ 2026-05-13 15:48 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Tue, Mar 03, 2026 at 10:25:17AM +0100, Igor Mammedov wrote:
> Date: Tue, 3 Mar 2026 10:25:17 +0100
> From: Igor Mammedov <imammedo@redhat.com>
> Subject: [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob
>
> replace blank table with a new one:
>
> +[000h 0000 4] Signature : "WDAT" [Watchdog Action Table]
> +[004h 0004 4] Table Length : 00000134
> +[008h 0008 1] Revision : 01
> +[009h 0009 1] Checksum : 31
> +[00Ah 0010 6] Oem ID : "BOCHS "
> +[010h 0016 8] Oem Table ID : "BXPC "
> +[018h 0024 4] Oem Revision : 00000001
> +[01Ch 0028 4] Asl Compiler ID : "BXPC"
> +[020h 0032 4] Asl Compiler Revision : 00000001
> +
> +[024h 0036 4] Header Length : 00000020
> +[028h 0040 2] PCI Segment : 00FF
> +[02Ah 0042 1] PCI Bus : FF
> +[02Bh 0043 1] PCI Device : FF
> +[02Ch 0044 1] PCI Function : FF
> +[02Dh 0045 3] Reserved : 000000
> +[030h 0048 4] Timer Period : 00000258
> +[034h 0052 4] Max Count : 000003FF
> +[038h 0056 4] Min Count : 00000004
> +[03Ch 0060 1] Flags (decoded below) : 81
> + Enabled : 1
> + Stopped When Asleep : 1
> +[03Dh 0061 3] Reserved : 000000
> +[040h 0064 4] Watchdog Entry Count : 0000000A
> +
> +[044h 0068 1] Watchdog Action : 01
> +[045h 0069 1] Instruction : 02
> +[046h 0070 2] Reserved : 0000
> +
> +[048h 0072 12] Register Region : [Generic Address Structure]
> +[048h 0072 1] Space ID : 01 [SystemIO]
> +[049h 0073 1] Bit Width : 10
> +[04Ah 0074 1] Bit Offset : 00
> +[04Bh 0075 1] Encoded Access Width : 02 [Word Access:16]
> +[04Ch 0076 8] Address : 0000000000000660
> +
> +[054h 0084 4] Value : 00000001
> +[058h 0088 4] Register Mask : 000001FF
> +
> +[05Ch 0092 1] Watchdog Action : 08
> +[05Dh 0093 1] Instruction : 00
> +[05Eh 0094 2] Reserved : 0000
> +
> +[060h 0096 12] Register Region : [Generic Address Structure]
> +[060h 0096 1] Space ID : 01 [SystemIO]
> +[061h 0097 1] Bit Width : 10
> +[062h 0098 1] Bit Offset : 00
> +[063h 0099 1] Encoded Access Width : 02 [Word Access:16]
> +[064h 0100 8] Address : 0000000000000668
> +
> +[06Ch 0108 4] Value : 00000000
> +[070h 0112 4] Register Mask : 00000800
> +
> +[074h 0116 1] Watchdog Action : 09
> +[075h 0117 1] Instruction : 82
> +[076h 0118 2] Reserved : 0000
> +
> +[078h 0120 12] Register Region : [Generic Address Structure]
> +[078h 0120 1] Space ID : 01 [SystemIO]
> +[079h 0121 1] Bit Width : 10
> +[07Ah 0122 1] Bit Offset : 00
> +[07Bh 0123 1] Encoded Access Width : 02 [Word Access:16]
> +[07Ch 0124 8] Address : 0000000000000668
> +
> +[084h 0132 4] Value : 00000000
> +[088h 0136 4] Register Mask : 00000800
> +
> +[08Ch 0140 1] Watchdog Action : 0A
> +[08Dh 0141 1] Instruction : 00
> +[08Eh 0142 2] Reserved : 0000
> +
> +[090h 0144 12] Register Region : [Generic Address Structure]
> +[090h 0144 1] Space ID : 01 [SystemIO]
> +[091h 0145 1] Bit Width : 10
> +[092h 0146 1] Bit Offset : 00
> +[093h 0147 1] Encoded Access Width : 02 [Word Access:16]
> +[094h 0148 8] Address : 0000000000000668
> +
> +[09Ch 0156 4] Value : 00000800
> +[0A0h 0160 4] Register Mask : 00000800
> +
> +[0A4h 0164 1] Watchdog Action : 0B
> +[0A5h 0165 1] Instruction : 82
> +[0A6h 0166 2] Reserved : 0000
> +
> +[0A8h 0168 12] Register Region : [Generic Address Structure]
> +[0A8h 0168 1] Space ID : 01 [SystemIO]
> +[0A9h 0169 1] Bit Width : 10
> +[0AAh 0170 1] Bit Offset : 00
> +[0ABh 0171 1] Encoded Access Width : 02 [Word Access:16]
> +[0ACh 0172 8] Address : 0000000000000668
> +
> +[0B4h 0180 4] Value : 00000800
> +[0B8h 0184 4] Register Mask : 00000800
> +
> +[0BCh 0188 1] Watchdog Action : 06
> +[0BDh 0189 1] Instruction : 03
> +[0BEh 0190 2] Reserved : 0000
> +
> +[0C0h 0192 12] Register Region : [Generic Address Structure]
> +[0C0h 0192 1] Space ID : 01 [SystemIO]
> +[0C1h 0193 1] Bit Width : 10
> +[0C2h 0194 1] Bit Offset : 00
> +[0C3h 0195 1] Encoded Access Width : 02 [Word Access:16]
> +[0C4h 0196 8] Address : 0000000000000672
> +
> +[0CCh 0204 4] Value : 00000000
> +[0D0h 0208 4] Register Mask : 000003FF
> +
> +[0D4h 0212 1] Watchdog Action : 05
> +[0D5h 0213 1] Instruction : 01
> +[0D6h 0214 2] Reserved : 0000
> +
> +[0D8h 0216 12] Register Region : [Generic Address Structure]
> +[0D8h 0216 1] Space ID : 01 [SystemIO]
> +[0D9h 0217 1] Bit Width : 10
> +[0DAh 0218 1] Bit Offset : 00
> +[0DBh 0219 1] Encoded Access Width : 02 [Word Access:16]
> +[0DCh 0220 8] Address : 0000000000000672
> +
> +[0E4h 0228 4] Value : 00000000
> +[0E8h 0232 4] Register Mask : 000003FF
> +
> +[0ECh 0236 1] Watchdog Action : 20
> +[0EDh 0237 1] Instruction : 00
> +[0EEh 0238 2] Reserved : 0000
> +
> +[0F0h 0240 12] Register Region : [Generic Address Structure]
> +[0F0h 0240 1] Space ID : 01 [SystemIO]
> +[0F1h 0241 1] Bit Width : 10
> +[0F2h 0242 1] Bit Offset : 00
> +[0F3h 0243 1] Encoded Access Width : 02 [Word Access:16]
> +[0F4h 0244 8] Address : 0000000000000666
> +
> +[0FCh 0252 4] Value : 00000002
> +[100h 0256 4] Register Mask : 00000002
> +
> +[104h 0260 1] Watchdog Action : 21
> +[105h 0261 1] Instruction : 82
> +[106h 0262 2] Reserved : 0000
> +
> +[108h 0264 12] Register Region : [Generic Address Structure]
> +[108h 0264 1] Space ID : 01 [SystemIO]
> +[109h 0265 1] Bit Width : 10
> +[10Ah 0266 1] Bit Offset : 00
> +[10Bh 0267 1] Encoded Access Width : 02 [Word Access:16]
> +[10Ch 0268 8] Address : 0000000000000666
> +
> +[114h 0276 4] Value : 00000002
> +[118h 0280 4] Register Mask : 00000002
> +
> +[11Ch 0284 1] Watchdog Action : 21
> +[11Dh 0285 1] Instruction : 82
> +[11Eh 0286 2] Reserved : 0000
> +
> +[120h 0288 12] Register Region : [Generic Address Structure]
> +[120h 0288 1] Space ID : 01 [SystemIO]
> +[121h 0289 1] Bit Width : 10
> +[122h 0290 1] Bit Offset : 00
> +[123h 0291 1] Encoded Access Width : 02 [Word Access:16]
> +[124h 0292 8] Address : 0000000000000666
> +
> +[12Ch 0300 4] Value : 00000004
> +[130h 0304 4] Register Mask : 00000004
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Acked-by: Ani Sinha <anisinha@redhat.com>
> ---
> tests/qtest/bios-tables-test-allowed-diff.h | 1 -
> tests/data/acpi/x86/q35/WDAT.wdat | Bin 0 -> 308 bytes
> 2 files changed, 1 deletion(-)
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table
2026-03-03 9:25 ` [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table Igor Mammedov
@ 2026-05-13 15:48 ` Zhao Liu
0 siblings, 0 replies; 33+ messages in thread
From: Zhao Liu @ 2026-05-13 15:48 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Tue, Mar 03, 2026 at 10:25:15AM +0100, Igor Mammedov wrote:
> Date: Tue, 3 Mar 2026 10:25:15 +0100
> From: Igor Mammedov <imammedo@redhat.com>
> Subject: [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Acked-by: Ani Sinha <anisinha@redhat.com>
> ---
> tests/qtest/bios-tables-test-allowed-diff.h | 1 +
> tests/data/acpi/x86/q35/WDAT.wdat | 0
> 2 files changed, 1 insertion(+)
> create mode 100644 tests/data/acpi/x86/q35/WDAT.wdat
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case
2026-03-03 9:25 ` [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case Igor Mammedov
@ 2026-05-13 15:49 ` Zhao Liu
0 siblings, 0 replies; 33+ messages in thread
From: Zhao Liu @ 2026-05-13 15:49 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, anisinha, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
On Tue, Mar 03, 2026 at 10:25:16AM +0100, Igor Mammedov wrote:
> Date: Tue, 3 Mar 2026 10:25:16 +0100
> From: Igor Mammedov <imammedo@redhat.com>
> Subject: [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> Reviewed-by: Ani Sinha <anisinha@redhat.com>
> ---
> tests/qtest/bios-tables-test.c | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH v2 02/21] x86: q35: add 'wdat' property
2026-05-13 14:58 ` Zhao Liu
@ 2026-05-14 7:16 ` Ani Sinha
0 siblings, 0 replies; 33+ messages in thread
From: Ani Sinha @ 2026-05-14 7:16 UTC (permalink / raw)
To: Zhao Liu
Cc: Igor Mammedov, qemu-devel, mst, pbonzini, peter.maydell,
shannon.zhaosl, philmd, rad, leif.lindholm, qemu-arm
> On 13 May 2026, at 8:28 PM, Zhao Liu <zhao1.liu@intel.com> wrote:
>
> On Tue, Mar 03, 2026 at 10:25:13AM +0100, Igor Mammedov wrote:
>> Date: Tue, 3 Mar 2026 10:25:13 +0100
>> From: Igor Mammedov <imammedo@redhat.com>
>> Subject: [PATCH v2 02/21] x86: q35: add 'wdat' property
>>
>> Used for enabling WDAT based watchdog for builtin iTCO watchdog.
>> Usage:
>> -M q35,wdat={on|off}
>> By default it is disabled.
>>
>> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
>> ---
>> include/hw/i386/pc.h | 1 +
>> hw/i386/pc_q35.c | 18 ++++++++++++++++++
>> 2 files changed, 19 insertions(+)
>
> Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2026-05-14 7:18 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-03 9:25 [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 01/21] acpi: add API to build WDAT instructions Igor Mammedov
2026-05-13 15:23 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 02/21] x86: q35: add 'wdat' property Igor Mammedov
2026-05-13 14:58 ` Zhao Liu
2026-05-14 7:16 ` Ani Sinha
2026-03-03 9:25 ` [PATCH v2 03/21] x86: q35: generate WDAT ACPI table Igor Mammedov
2026-05-13 15:47 ` Zhao Liu
2026-05-13 15:28 ` Michael S. Tsirkin
2026-03-03 9:25 ` [PATCH v2 04/21] tests: acpi: x86/q35: whitelist new WDAT table Igor Mammedov
2026-05-13 15:48 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 05/21] tests: acpi: x86/q35: add WDAT table test case Igor Mammedov
2026-05-13 15:49 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 06/21] tests: acpi: x86/q35: update expected WDAT blob Igor Mammedov
2026-05-13 15:48 ` Zhao Liu
2026-03-03 9:25 ` [PATCH v2 07/21] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 08/21] arm: add tracing events to sbsa_gwdt Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 09/21] arm: virt: create sbsa_gwdt watchdog Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 10/21] arm: sbsa_gwdt: add 'wdat' option Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 11/21] arm: virt: add support for WDAT based watchdog Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 12/21] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 13/21] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 14/21] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 15/21] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 16/21] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 17/21] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 18/21] sbsa_gwdt: reduce code ident Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 19/21] sbsa_gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 20/21] sbsa_gwdt: reschedule timer on direct WCV load Igor Mammedov
2026-03-03 9:25 ` [PATCH v2 21/21] sbsa_gwdt: limit compare_value to INT64_MAX Igor Mammedov
2026-04-28 14:12 ` [PATCH v2 00/21] Introduce ACPI watchdog for Q35 and arm/virt boards Igor Mammedov
2026-05-12 13:30 ` Igor Mammedov
2026-05-12 14:45 ` Ani Sinha
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox