* [PATCH v3 00/17] Add watchdog support to arm/virt board
@ 2026-06-24 10:28 Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 01/17] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
` (16 more replies)
0 siblings, 17 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
This series adds SBSA GWDT to the arm/virt machine with a WDAT table
tailored for it and necessary tweaks to make it usable with the
WDAT driver.
In addition to WDAT, it also adds a native variant with GWDT
described in FDT and GTDT (works on Linux, broken on Windows
without patches 16-17).
Patches 14-17 fix GWDT handling of direct WCV register writes
to match the SBSA spec. This fixes Windows 11 reboots when GWDT
is present without WDAT.
This is making GTDT watchdog sort of 'work' with Windows, modulo
that Windows sets timeout too far in the future, so in practice
watchdog would never trigger. (WDAT variant doesn't have this
issue).
One can test it launching VM with:
-device sbsa-gwdt,wdat=on
to trace access to GWDT registers add:
-trace "sbsa_gwdt*"
To verify the guest uses watchdog use following steps to trigger
watchdog reboot:
* on Linux: enable watchdog service, check with wdctl, then:
echo c > /proc/sysrq-trigger
* on Windows: kill svchost in admin mode 'cmd' shell:
taskkill /f /im svchost.exe
Tested with Fedora 43 & Windows 11 (aarch64, KVM on Jetson)
git tree: https://gitlab.com/imammedo/qemu/-/commits/gwdt_v3
1) http://msdn.microsoft.com/en-us/windows/hardware/gg463320.aspx
Changelog:
v3:
* drop x86 patches (already merged)
* (Eric) rename device type from sbsa_gwdt to sbsa-gwdt (new patch 3)
* arm: virt: create sbsa-gwdt watchdog (patch 4):
- (Eric) assign MMIO/IRQ statically, drop dynamic sysbus machinery
- (Peter) set watchdog freq to system counter clock explicitly
* arm: sbsa-gwdt: add 'wdat' option (patch 5):
- split out from v2's monolithic patch 11
* acpi: introduce WDAT table for GWDT (patch 6):
- (Eric) split out from v2's patch 11
- add/improve comments
- use 'freq' argument passed down by caller
- simplify magic val on WRR write and add comment
- group table records by used register
* arm: virt: add support for WDAT based watchdog (patch 7):
- (Eric) split out from v2's patch 11
- skip FDT watchdog node creation in wdat mode
- skip setting cntfrq clock-frequency in wdat mode
* sbsa-gwdt: reschedule timer on direct WCV load (patch 16):
- improved commit message with spec references and
description of Windows GTDT-mode behavior
* sbsa-gwdt: limit compare_value to INT64_MAX (patch 17):
- rewritten commit message: document QEMU timer API
limitation vs spec, Windows write sequence, and
vCPU preemption fragility under virtualization
v2:
* ditch generic '-machine acpi-watchdog' option in favor of
board specific: arm/virt: -device sbsa_gwdt,wdat={on|off}
* arm/virt: add FDT and GTDT ACPI entries for GWDT
* arm/virt: add test case for GTDT
* optional GWDT cleanup/fixes for WCV register update
previous revisions:
v2: https://patchew.org/QEMU/20260303092532.2410177-1-imammedo@redhat.com/
v1: https://patchew.org/QEMU/20260206131438.1857182-1-imammedo@redhat.com/
Igor Mammedov (17):
arm: sbsa_gwdt: fixup default "clock-frequency"
arm: add tracing events to sbsa_gwdt
arm: sbsa_gwdt: rename device type to sbsa-gwdt
arm: virt: create sbsa-gwdt watchdog
arm: sbsa-gwdt: add 'wdat' option
acpi: introduce WDAT table for GWDT
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/arm/virt.h | 3 +
include/hw/watchdog/sbsa_gwdt.h | 3 +-
hw/acpi/meson.build | 2 +
hw/acpi/wdat-gwdt-stub.c | 16 ++++
hw/acpi/wdat-gwdt.c | 99 +++++++++++++++++++++++++
hw/arm/Kconfig | 1 +
hw/arm/virt-acpi-build.c | 51 ++++++++++++-
hw/arm/virt.c | 39 ++++++++++
hw/core/sysbus-fdt.c | 2 +
hw/watchdog/sbsa_gwdt.c | 66 +++++++++++------
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/qtest/bios-tables-test.c | 41 ++++++++++
15 files changed, 325 insertions(+), 26 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
create mode 100644 tests/data/acpi/aarch64/virt/GTDT.gwdt
create mode 100644 tests/data/acpi/aarch64/virt/WDAT.wdat
--
2.47.3
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v3 01/17] arm: sbsa_gwdt: fixup default "clock-frequency"
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 02/17] arm: add tracing events to sbsa_gwdt Igor Mammedov
` (15 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
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. (not that it does matter, since users are
setting frequency to match CPU's one explicitly)
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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] 32+ messages in thread
* [PATCH v3 02/17] arm: add tracing events to sbsa_gwdt
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 01/17] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt Igor Mammedov
` (14 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Ani Sinha, Eric Auger
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <anisinha@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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 d85b3ca769..b388f7b250 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -42,3 +42,12 @@ k230_wdt_interrupt(void) "K230 WDT interrupt"
k230_wdt_reset(void) "K230 WDT system reset"
k230_wdt_restart(void) "K230 WDT restart"
k230_wdt_reset_device(void) "K230 WDT device reset"
+
+#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] 32+ messages in thread
* [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 01/17] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 02/17] arm: add tracing events to sbsa_gwdt Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 8:12 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog Igor Mammedov
` (13 subsequent siblings)
16 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
Use hyphenated name to follow QEMU device naming convention.
Migration compatibility is preserved since the vmstate name
is already "sbsa-gwdt".
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
include/hw/watchdog/sbsa_gwdt.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
index 307a4f291a..8941dcff9e 100644
--- a/include/hw/watchdog/sbsa_gwdt.h
+++ b/include/hw/watchdog/sbsa_gwdt.h
@@ -16,7 +16,7 @@
#include "hw/core/sysbus.h"
#include "hw/core/irq.h"
-#define TYPE_WDT_SBSA "sbsa_gwdt"
+#define TYPE_WDT_SBSA "sbsa-gwdt"
#define SBSA_GWDT(obj) \
OBJECT_CHECK(SBSA_GWDTState, (obj), TYPE_WDT_SBSA)
#define SBSA_GWDT_CLASS(klass) \
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (2 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 8:37 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 05/17] arm: sbsa-gwdt: add 'wdat' option Igor Mammedov
` (12 subsequent siblings)
16 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, 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.
Instead of using dynamic sysbus infra to wire up MMIO/IRQ/FDT,
statically assign resources in machine's mem/irq maps and wire
them up at device (pre_)plug handlers. It's similar to dynamic
sysbus wiring, modulo resources are nailed down statically,
and wiring is limited to virt machine only.
(Benefit is that tests don't break anymore on rebase due to
address being stable)
Tested with Fedora 43:
FDT: -M virt,acpi=off -device sbsa-gwdt
ACPI: -M virt -device sbsa-gwdt
Note:
Windows sees GTDT, initializes watchdog but instead pinging WRR
it sets/advances WOR to way too large value, so it's never going
to trigger watchdog reboot (it's Windows driver issue though).
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
v3:
- (Eric) assign MMIO/IRQ statically and abandon most of
dynamic sysbus machinery.
- (Peter) set watchdog freq to system clock explicitly,
machine version compat won't work in case host is not runing
1GHz clock. (Tested on Jetson machine)
---
include/hw/arm/virt.h | 3 +++
hw/arm/Kconfig | 1 +
hw/arm/virt-acpi-build.c | 29 +++++++++++++++++++++++++++--
hw/arm/virt.c | 37 +++++++++++++++++++++++++++++++++++++
hw/core/sysbus-fdt.c | 2 ++
hw/watchdog/sbsa_gwdt.c | 1 +
6 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 171d44c644..22e66d1a11 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -97,6 +97,9 @@ enum {
VIRT_NVDIMM_ACPI,
VIRT_PVTIME,
VIRT_ACPI_PCIHP,
+ VIRT_GWDT_WS0,
+ VIRT_GWDT_REFRESH,
+ VIRT_GWDT_CONTROL,
VIRT_LOWMEMMAP_LAST,
};
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 500bfdfe2a..962a39247c 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 99490aa7b1..f5b3b4ce48 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"
#include "smmuv3-accel.h"
#include "tegra241-cmdqv.h"
@@ -868,6 +869,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);
@@ -898,10 +901,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);
@@ -911,6 +919,23 @@ 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) {
+ hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
+ hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
+ int irq = ARM_SPI_BASE + vms->irqmap[VIRT_GWDT_WS0];
+
+ 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 d8d27f2ef6..aacf9b7251 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" },
@@ -214,6 +215,8 @@ static const MemMapEntry base_memmap[] = {
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
[VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 },
+ [VIRT_GWDT_REFRESH] = { 0x0f000000, 0x00001000 },
+ [VIRT_GWDT_CONTROL] = { 0x0f001000, 0x00001000 },
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
@@ -267,6 +270,7 @@ static const int a15irqmap[] = {
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
+ [VIRT_GWDT_WS0] = 10,
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
@@ -3820,6 +3824,10 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
qlist_append_str(reserved_regions, resv_prop_str);
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
g_free(resv_prop_str);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
+ uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
+ "cntfrq", &error_abort);
+ qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
error_setg(errp, "virt machine already has %s set. "
@@ -3871,6 +3879,34 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
{
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+ if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
+ MachineState *ms = MACHINE(vms);
+ hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
+ hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
+ int irq = vms->irqmap[VIRT_GWDT_WS0];
+
+ sysbus_mmio_map(s, 0, rbase);
+ sysbus_mmio_map(s, 1, cbase);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+
+ {
+ char *nodename = g_strdup_printf("/watchdog@%" PRIx64, cbase);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename,
+ "compatible", "arm,sbsa-gwdt");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+ 2, cbase, 2, SBSA_GWDT_CMMIO_SIZE,
+ 2, rbase, 2, SBSA_GWDT_RMMIO_SIZE);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "timeout-sec", 30);
+ g_free(nodename);
+ }
+ }
+
if (vms->platform_bus_dev) {
MachineClass *mc = MACHINE_GET_CLASS(vms);
@@ -4123,6 +4159,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..12238570b5 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
@@ -140,6 +141,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, no_fdt_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] 32+ messages in thread
* [PATCH v3 05/17] arm: sbsa-gwdt: add 'wdat' option
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (3 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 06/17] acpi: introduce WDAT table for GWDT Igor Mammedov
` (11 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
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>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
include/hw/watchdog/sbsa_gwdt.h | 1 +
hw/watchdog/sbsa_gwdt.c | 9 +++++++++
2 files changed, 10 insertions(+)
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
index 8941dcff9e..5ad7c7a798 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..1678ab85db 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -265,6 +265,14 @@ static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq);
+ /*
+ * WDAT spec: "The clock interval that the WDT uses must be
+ * greater than or equal to 1 millisecond."
+ */
+ if (s->wdat) {
+ s->freq = 1000;
+ }
+
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
dev);
}
@@ -276,6 +284,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] 32+ messages in thread
* [PATCH v3 06/17] acpi: introduce WDAT table for GWDT
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (4 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 05/17] arm: sbsa-gwdt: add 'wdat' option Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 12:07 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog Igor Mammedov
` (10 subsequent siblings)
16 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
Add build_gwdt_wdat() to generate a Watchdog Action Table
tailored for the SBSA Generic Watchdog Timer.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
v3:
(Eric)
- split '[PATCH v2 11/21] arm: virt: add support for WDAT based watchdog'
on smaller chunks.
- add/improve comments where requested
- actualy use 'freq' argument passed down by caller
- simplify magic val on WRR write and add comment
- group table records by used register
---
include/hw/acpi/wdat-gwdt.h | 19 +++++++
hw/acpi/meson.build | 2 +
hw/acpi/wdat-gwdt-stub.c | 16 ++++++
hw/acpi/wdat-gwdt.c | 99 +++++++++++++++++++++++++++++++++++++
4 files changed, 136 insertions(+)
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 0c7bfb278a..09ad488a04 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -31,11 +31,13 @@ acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'))
stub_ss.add(files('ipmi-stub.c'))
stub_ss.add(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
stub_ss.add(files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c'))
stub_ss.add(files('pci-bridge-stub.c'))
+stub_ss.add(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'))
stub_ss.add(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..b30566ef6a
--- /dev/null
+++ b/hw/acpi/wdat-gwdt.c
@@ -0,0 +1,99 @@
+/*
+ * 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 */
+ /*
+ * PCI location fields are set to 0xff to indicate
+ * that the watchdog is not a PCI device.
+ */
+ 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: "The clock interval that the WDT uses must be
+ * greater than or equal to 1 millisecond."
+ */
+ g_assert(freq <= 1000);
+ /* Timer Period, ms */
+ build_append_int_noprefix(table_data, 1000 / freq, 4);
+ /*
+ * WDAT spec: "The time-out period before the WDT fires is recommended
+ * to be at least 5 minutes."
+ * Set max count to 10min and min count 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 | 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, 8, 4);
+ /* Action table: WCS (control/status) register actions */
+ 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_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);
+ /* WOR (offset) and WRR (refresh) register actions */
+ build_append_wdat_ins(table_data, WDAT_ACTION_SET_COUNTDOWN_PERIOD,
+ WDAT_INS_WRITE_COUNTDOWN,
+ wor_l, 0, 0xffffffff);
+ /* WRR: any write refreshes the watchdog, value is ignored */
+ build_append_wdat_ins(table_data, WDAT_ACTION_RESET,
+ WDAT_INS_WRITE_VALUE,
+ wrr, 0x1, 0x1);
+ 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);
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (5 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 06/17] acpi: introduce WDAT table for GWDT Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 12:15 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 08/17] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
` (9 subsequent siblings)
16 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
Add WDAT handling for sbsa-gwdt on arm/virt machine.
WDAT mode is enabled by 'wdat' option: ex: "-device sbsa-gwdt,wdat=on"
When WDAT is enabled:
- Build the WDAT ACPI table instead of the GTDT watchdog entry,
since they are mutually exclusive due to different timer
resolution (WDAT uses 1 kHz vs GTDT's system counter frequency).
- Skip FDT watchdog node creation, as the DT-based Linux driver
would use the system counter frequency which doesn't match the
WDAT-mode 1 kHz clock.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
v3:
- Skip FDT watchdog node creation in wdat mode
(Eric)
- wiring part of larger '[PATCH v2 11/21] arm: virt: add support for WDAT based watchdog'
---
hw/arm/virt-acpi-build.c | 34 ++++++++++++++++++++++++++--------
hw/arm/virt.c | 10 ++++++----
2 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f5b3b4ce48..71706b98e6 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"
#include "smmuv3-accel.h"
#include "tegra241-cmdqv.h"
@@ -859,7 +860,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
* 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
@@ -870,7 +872,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);
@@ -903,12 +904,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 */
@@ -921,7 +922,7 @@ 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) {
+ if (add_watchdog) {
hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
int irq = ARM_SPI_BASE + vms->irqmap[VIRT_GWDT_WS0];
@@ -1332,13 +1333,19 @@ 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);
CPUCoreCaches caches[CPU_MAX_CACHES];
unsigned int num_caches;
+ Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL);
num_caches = virt_get_caches(vms, caches);
+ if (wdt) {
+ has_wdat = object_property_get_bool(wdt, "wdat", &error_abort);
+ }
+
table_offsets = g_array_new(false, true /* clear */,
sizeof(uint32_t));
@@ -1357,6 +1364,17 @@ 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) {
+ uint64_t freq = object_property_get_uint(wdt, "clock-frequency",
+ &error_abort);
+ build_gwdt_wdat(tables_blob, tables->linker,
+ vms->oem_id, vms->oem_table_id,
+ vms->memmap[VIRT_GWDT_REFRESH].base,
+ vms->memmap[VIRT_GWDT_CONTROL].base,
+ freq);
+ }
+
if (!vmc->no_cpu_topology) {
acpi_add_table(table_offsets, tables_blob);
build_pptt(tables_blob, tables->linker, ms, vms->oem_id,
@@ -1364,7 +1382,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);
{
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index aacf9b7251..35ded6d1d4 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -3825,9 +3825,11 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
g_free(resv_prop_str);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
- uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
- "cntfrq", &error_abort);
- qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
+ if (!object_property_get_bool(OBJECT(dev), "wdat", &error_abort)) {
+ uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
+ "cntfrq", &error_abort);
+ qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
+ }
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
error_setg(errp, "virt machine already has %s set. "
@@ -3890,7 +3892,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
sysbus_mmio_map(s, 1, cbase);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
- {
+ if (!object_property_get_bool(OBJECT(dev), "wdat", &error_abort)) {
char *nodename = g_strdup_printf("/watchdog@%" PRIx64, cbase);
qemu_fdt_add_subnode(ms->fdt, nodename);
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 08/17] tests: acpi: arm/virt: whitelist new WDAT table
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (6 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 09/17] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
` (8 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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] 32+ messages in thread
* [PATCH v3 09/17] tests: acpi: arm/virt: add WDAT table test case
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (7 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 08/17] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
` (7 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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 af6d9b5136..5440aab2f8 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2275,6 +2275,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 = {
@@ -2893,6 +2912,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] 32+ messages in thread
* [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (8 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 09/17] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 12:16 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 11/17] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
` (6 subsequent siblings)
16 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, 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..d5adacf9114637d8803d08906ff1e29ac61f5fe0 100644
GIT binary patch
literal 260
zcmZXOK@NgI3`O4vF`x@byg*$Mjv=^kCkZBU9awQJZ&p(1B&bcAwm<K;ecx}dG(f1E
zXZz@-8M;<PBmmZ16+lr{z~)btGhbi?GEanrk^*Op%cs@+r=JYk@zHbs;iGQ%_k0R#
Y9+OSa{H}$nYB)I0_dnOT-}Sg>0T&h&0RR91
literal 0
HcmV?d00001
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 11/17] tests: acpi: arm/virt: whitelist GTDT table
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (9 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 12/17] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
` (5 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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] 32+ messages in thread
* [PATCH v3 12/17] tests: acpi: arm/virt: add GTDT watchdog table test case
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (10 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 11/17] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 13/17] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
` (4 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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 5440aab2f8..94fc95c8e1 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2294,6 +2294,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 = {
@@ -2914,6 +2932,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] 32+ messages in thread
* [PATCH v3 13/17] tests: acpi: arm/virt: update expected GTDT blob
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (11 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 12/17] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 14/17] sbsa-gwdt: reduce code ident Igor Mammedov
` (3 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
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>
Reviewed-by: Eric Auger <eric.auger@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..44e6f2b18d2848f595a8c69bdb54a59e1becaffd
GIT binary patch
literal 132
zcmXwwyA6Oq3`5@udZ_s+HDlZ%K?f37Fam?H1k-{Nf(yUca^^hc3n=cmre&9SY)M2U
h0D3DQ7eKED3_uCAo*U=C)xXm_Rp<<rdHr#;057;f7y$qP
literal 0
HcmV?d00001
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 14/17] sbsa-gwdt: reduce code ident
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (12 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 13/17] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
` (2 subsequent siblings)
16 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm, Eric Auger
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@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 1678ab85db..6113dcd077 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] 32+ messages in thread
* [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (13 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 14/17] sbsa-gwdt: reduce code ident Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 14:03 ` Eric Auger
2026-06-29 14:51 ` Peter Maydell
2026-06-24 10:28 ` [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX Igor Mammedov
16 siblings, 2 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
No functional change, just code reorganization to
prepare for direct WCV load support in the next commit.
While at it, simplify timeout calculations
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index 6113dcd077..5ee0e06af5 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -109,22 +109,18 @@ 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)))) {
+ 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 the current timeout value into compare registers */
s->wcvu = timeout >> 32;
s->wcvl = timeout;
}
+
+ timeout = (uint64_t)s->wcvu << 32 | s->wcvl;
timer_mod(s->timer, timeout);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (14 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 14:08 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX Igor Mammedov
16 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, 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"
QEMU accepts writes to WCV but doesn't reschedule the timer,
which it should per the spec pseudo code:
"TimeoutRefresh = ( SystemCounter [63:0] > CompareValue [63:0])"
Fix it by updating the timer on WCV write.
Fixes Windows in GTDT mode, which never issues a WRR refresh.
Instead, it programs WOR to ~4 sec, enables WCS, and immediately
writes a large absolute value into WCV to push the timeout far
into the future. Without this fix, QEMU ignores the WCV write,
the short WOR expires, and the guest reboots unexpectedly.
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 | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index 5ee0e06af5..fb67db9672 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)
@@ -167,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] 32+ messages in thread
* [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
` (15 preceding siblings ...)
2026-06-24 10:28 ` [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load Igor Mammedov
@ 2026-06-24 10:28 ` Igor Mammedov
2026-06-29 14:10 ` Eric Auger
2026-06-29 14:48 ` Peter Maydell
16 siblings, 2 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-24 10:28 UTC (permalink / raw)
To: qemu-devel
Cc: mst, eauger, peter.maydell, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
QEMU timer subsystem uses int64_t, so WCV values with bit 63 set
overflow and cause the timer to fire immediately. The SBSA spec
defines WCV as an unsigned 64-bit compare value, so such values
are valid per spec and represent far-future deadlines (however
unpractical).
Windows in GTDT mode writes WCV in two 32-bit halves while the
watchdog is running:
sbsa-gwdt_control_write [0x8] <- 0xffffffff # WOR (~4 sec)
sbsa-gwdt_control_write [0x0] <- 0x1 # WCS enable
sbsa-gwdt_control_write [0x14] <- 0xffffffff # WCVU (intermediate)
sbsa-gwdt_control_write [0x10] <- 0xa906ca28 # WCVL
sbsa-gwdt_control_write [0x14] <- 0xecb1 # WCVU (final)
The intermediate WCVU write (0xffffffff) creates a WCV above
INT64_MAX, which overflows QEMU's signed timer and fires
immediately — triggering WS0 => WS1 => reboot before the final
WCVU write lands.
Clamp WCV to INT64_MAX to avoid timer API overflow.
Note: Windows' GTDT watchdog usage is also fragile under
virtualization. It programs a short WOR (~4 sec), enables WCS,
and relies on a subsequent WCV write to push the deadline far
into the future — never using WRR for explicit refresh. On bare
metal the WCS=>WCV gap is negligible, but in a VM the vCPU can
be preempted between MMIO accesses while the clock keeps
ticking, potentially expiring the short WOR timeout before the
WCV override lands.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
hw/watchdog/sbsa_gwdt.c | 2 ++
tests/qtest/bios-tables-test.c | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index fb67db9672..ff7adbcb0f 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);
}
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index 94fc95c8e1..370b0fd2e6 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -2308,7 +2308,7 @@ static void test_acpi_aarch64_virt_tcg_gtdt_wd(void)
.scan_len = 128ULL * MiB,
};
- test_acpi_one("-cpu cortex-a57 " "-device sbsa-gwdt", &data);
+ test_acpi_one("-cpu cortex-a57 -device sbsa-gwdt", &data);
free_test_data(&data);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 32+ messages in thread
* Re: [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt
2026-06-24 10:28 ` [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt Igor Mammedov
@ 2026-06-29 8:12 ` Eric Auger
0 siblings, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 8:12 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> Use hyphenated name to follow QEMU device naming convention.
> Migration compatibility is preserved since the vmstate name
> is already "sbsa-gwdt".
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
> ---
> include/hw/watchdog/sbsa_gwdt.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
> index 307a4f291a..8941dcff9e 100644
> --- a/include/hw/watchdog/sbsa_gwdt.h
> +++ b/include/hw/watchdog/sbsa_gwdt.h
> @@ -16,7 +16,7 @@
> #include "hw/core/sysbus.h"
> #include "hw/core/irq.h"
>
> -#define TYPE_WDT_SBSA "sbsa_gwdt"
> +#define TYPE_WDT_SBSA "sbsa-gwdt"
> #define SBSA_GWDT(obj) \
> OBJECT_CHECK(SBSA_GWDTState, (obj), TYPE_WDT_SBSA)
> #define SBSA_GWDT_CLASS(klass) \
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog
2026-06-24 10:28 ` [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog Igor Mammedov
@ 2026-06-29 8:37 ` Eric Auger
2026-06-29 13:36 ` Igor Mammedov
0 siblings, 1 reply; 32+ messages in thread
From: Eric Auger @ 2026-06-29 8:37 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
Hi Igor,
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> 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.
>
> Instead of using dynamic sysbus infra to wire up MMIO/IRQ/FDT,
> statically assign resources in machine's mem/irq maps and wire
> them up at device (pre_)plug handlers. It's similar to dynamic
> sysbus wiring, modulo resources are nailed down statically,
> and wiring is limited to virt machine only.
> (Benefit is that tests don't break anymore on rebase due to
> address being stable)
>
> Tested with Fedora 43:
> FDT: -M virt,acpi=off -device sbsa-gwdt
> ACPI: -M virt -device sbsa-gwdt
>
> Note:
> Windows sees GTDT, initializes watchdog but instead pinging WRR
> it sets/advances WOR to way too large value, so it's never going
> to trigger watchdog reboot (it's Windows driver issue though).
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> v3:
> - (Eric) assign MMIO/IRQ statically and abandon most of
> dynamic sysbus machinery.
> - (Peter) set watchdog freq to system clock explicitly,
> machine version compat won't work in case host is not runing
> 1GHz clock. (Tested on Jetson machine)
> ---
> include/hw/arm/virt.h | 3 +++
> hw/arm/Kconfig | 1 +
> hw/arm/virt-acpi-build.c | 29 +++++++++++++++++++++++++++--
> hw/arm/virt.c | 37 +++++++++++++++++++++++++++++++++++++
> hw/core/sysbus-fdt.c | 2 ++
> hw/watchdog/sbsa_gwdt.c | 1 +
> 6 files changed, 71 insertions(+), 2 deletions(-)
>
> diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
> index 171d44c644..22e66d1a11 100644
> --- a/include/hw/arm/virt.h
> +++ b/include/hw/arm/virt.h
> @@ -97,6 +97,9 @@ enum {
> VIRT_NVDIMM_ACPI,
> VIRT_PVTIME,
> VIRT_ACPI_PCIHP,
> + VIRT_GWDT_WS0,
> + VIRT_GWDT_REFRESH,
> + VIRT_GWDT_CONTROL,
> VIRT_LOWMEMMAP_LAST,
> };
>
> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index 500bfdfe2a..962a39247c 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 99490aa7b1..f5b3b4ce48 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"
>
> #include "smmuv3-accel.h"
> #include "tegra241-cmdqv.h"
> @@ -868,6 +869,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);
>
> @@ -898,10 +901,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);
> @@ -911,6 +919,23 @@ 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) {
> + hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
> + hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
> + int irq = ARM_SPI_BASE + vms->irqmap[VIRT_GWDT_WS0];
> +
> + 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 d8d27f2ef6..aacf9b7251 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" },
> @@ -214,6 +215,8 @@ static const MemMapEntry base_memmap[] = {
> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
> [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
> [VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 },
> + [VIRT_GWDT_REFRESH] = { 0x0f000000, 0x00001000 },
> + [VIRT_GWDT_CONTROL] = { 0x0f001000, 0x00001000 },
> [VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
> [VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
> [VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
> @@ -267,6 +270,7 @@ static const int a15irqmap[] = {
> [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
> [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
> [VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
> + [VIRT_GWDT_WS0] = 10,
nit: move that after [VIRT_ACPI_GED] = 9,
> [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
> };
>
> @@ -3820,6 +3824,10 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> qlist_append_str(reserved_regions, resv_prop_str);
> qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
> g_free(resv_prop_str);
> + } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
> + uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
> + "cntfrq", &error_abort);
missing extra line.
> + qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
Can you explain why you cannot do that in virt_machine_device_plug_cb()?
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
> if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
> error_setg(errp, "virt machine already has %s set. "
> @@ -3871,6 +3879,34 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
> {
> VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
>
> + if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
> + SysBusDevice *s = SYS_BUS_DEVICE(dev);
> + MachineState *ms = MACHINE(vms);
> + hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
> + hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
> + int irq = vms->irqmap[VIRT_GWDT_WS0];
> +
> + sysbus_mmio_map(s, 0, rbase);
> + sysbus_mmio_map(s, 1, cbase);
> + sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
> +
> + {
> + char *nodename = g_strdup_printf("/watchdog@%" PRIx64, cbase);
> +
> + qemu_fdt_add_subnode(ms->fdt, nodename);
> + qemu_fdt_setprop_string(ms->fdt, nodename,
> + "compatible", "arm,sbsa-gwdt");
> + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
> + 2, cbase, 2, SBSA_GWDT_CMMIO_SIZE,
> + 2, rbase, 2, SBSA_GWDT_RMMIO_SIZE);
> + qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
> + GIC_FDT_IRQ_TYPE_SPI, irq,
> + GIC_FDT_IRQ_FLAGS_LEVEL_HI);
> + qemu_fdt_setprop_cell(ms->fdt, nodename, "timeout-sec", 30);
> + g_free(nodename);
I would create a separate helper just as create_virtio_iommu_dt_bindings()
> + }
> + }
> +
> if (vms->platform_bus_dev) {
> MachineClass *mc = MACHINE_GET_CLASS(vms);
>
> @@ -4123,6 +4159,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..12238570b5 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
> @@ -140,6 +141,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, no_fdt_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";
You may document somewhere that the device can be dynamically
instantiated, in machvirt alone and this required machine specific
hardwiring.
Thanks
Eric
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 06/17] acpi: introduce WDAT table for GWDT
2026-06-24 10:28 ` [PATCH v3 06/17] acpi: introduce WDAT table for GWDT Igor Mammedov
@ 2026-06-29 12:07 ` Eric Auger
0 siblings, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 12:07 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> Add build_gwdt_wdat() to generate a Watchdog Action Table
> tailored for the SBSA Generic Watchdog Timer.
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> v3:
> (Eric)
> - split '[PATCH v2 11/21] arm: virt: add support for WDAT based watchdog'
> on smaller chunks.
> - add/improve comments where requested
> - actualy use 'freq' argument passed down by caller
> - simplify magic val on WRR write and add comment
> - group table records by used register
> ---
> include/hw/acpi/wdat-gwdt.h | 19 +++++++
> hw/acpi/meson.build | 2 +
> hw/acpi/wdat-gwdt-stub.c | 16 ++++++
> hw/acpi/wdat-gwdt.c | 99 +++++++++++++++++++++++++++++++++++++
> 4 files changed, 136 insertions(+)
> 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 0c7bfb278a..09ad488a04 100644
> --- a/hw/acpi/meson.build
> +++ b/hw/acpi/meson.build
> @@ -31,11 +31,13 @@ acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
> acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'))
> stub_ss.add(files('ipmi-stub.c'))
> stub_ss.add(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
> stub_ss.add(files('acpi-stub.c', 'aml-build-stub.c', 'ghes-stub.c'))
> stub_ss.add(files('pci-bridge-stub.c'))
> +stub_ss.add(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'))
> stub_ss.add(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..b30566ef6a
> --- /dev/null
> +++ b/hw/acpi/wdat-gwdt.c
> @@ -0,0 +1,99 @@
> +/*
> + * 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)'
nit: alignment is a bit strange + leading blanks
> + */
> +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 */
> + /*
> + * PCI location fields are set to 0xff to indicate
> + * that the watchdog is not a PCI device.
> + */
> + 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: "The clock interval that the WDT uses must be
> + * greater than or equal to 1 millisecond."
> + */
> + g_assert(freq <= 1000);
> + /* Timer Period, ms */
> + build_append_int_noprefix(table_data, 1000 / freq, 4);
> + /*
> + * WDAT spec: "The time-out period before the WDT fires is recommended
> + * to be at least 5 minutes."
> + * Set max count to 10min and min count 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 | 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, 8, 4);
> + /* Action table: WCS (control/status) register actions */
> + 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_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);
> + /* WOR (offset) and WRR (refresh) register actions */
> + build_append_wdat_ins(table_data, WDAT_ACTION_SET_COUNTDOWN_PERIOD,
> + WDAT_INS_WRITE_COUNTDOWN,
> + wor_l, 0, 0xffffffff);
> + /* WRR: any write refreshes the watchdog, value is ignored */
> + build_append_wdat_ins(table_data, WDAT_ACTION_RESET,
> + WDAT_INS_WRITE_VALUE,
> + wrr, 0x1, 0x1);
> + 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);
> +}
Besides, looks good to me after your additional information on my
comments/questions on v2
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Thanks
Eric
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog
2026-06-24 10:28 ` [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog Igor Mammedov
@ 2026-06-29 12:15 ` Eric Auger
0 siblings, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 12:15 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> Add WDAT handling for sbsa-gwdt on arm/virt machine.
>
> WDAT mode is enabled by 'wdat' option: ex: "-device sbsa-gwdt,wdat=on"
>
> When WDAT is enabled:
> - Build the WDAT ACPI table instead of the GTDT watchdog entry,
> since they are mutually exclusive due to different timer
> resolution (WDAT uses 1 kHz vs GTDT's system counter frequency).
> - Skip FDT watchdog node creation, as the DT-based Linux driver
> would use the system counter frequency which doesn't match the
> WDAT-mode 1 kHz clock.
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> v3:
> - Skip FDT watchdog node creation in wdat mode
> (Eric)
> - wiring part of larger '[PATCH v2 11/21] arm: virt: add support for WDAT based watchdog'
> ---
> hw/arm/virt-acpi-build.c | 34 ++++++++++++++++++++++++++--------
> hw/arm/virt.c | 10 ++++++----
> 2 files changed, 32 insertions(+), 12 deletions(-)
>
> diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
> index f5b3b4ce48..71706b98e6 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"
>
> #include "smmuv3-accel.h"
> #include "tegra241-cmdqv.h"
> @@ -859,7 +860,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
> * 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)
wdt is not used anymore
With that fixed
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Thanks
Eric
> {
> /*
> * Table 5-117 Flag Definitions
> @@ -870,7 +872,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);
>
> @@ -903,12 +904,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 */
> @@ -921,7 +922,7 @@ 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) {
> + if (add_watchdog) {
> hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
> hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
> int irq = ARM_SPI_BASE + vms->irqmap[VIRT_GWDT_WS0];
> @@ -1332,13 +1333,19 @@ 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);
> CPUCoreCaches caches[CPU_MAX_CACHES];
> unsigned int num_caches;
> + Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL);
>
> num_caches = virt_get_caches(vms, caches);
>
> + if (wdt) {
> + has_wdat = object_property_get_bool(wdt, "wdat", &error_abort);
> + }
> +
> table_offsets = g_array_new(false, true /* clear */,
> sizeof(uint32_t));
>
> @@ -1357,6 +1364,17 @@ 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) {
> + uint64_t freq = object_property_get_uint(wdt, "clock-frequency",
> + &error_abort);
> + build_gwdt_wdat(tables_blob, tables->linker,
> + vms->oem_id, vms->oem_table_id,
> + vms->memmap[VIRT_GWDT_REFRESH].base,
> + vms->memmap[VIRT_GWDT_CONTROL].base,
> + freq);
> + }
> +
> if (!vmc->no_cpu_topology) {
> acpi_add_table(table_offsets, tables_blob);
> build_pptt(tables_blob, tables->linker, ms, vms->oem_id,
> @@ -1364,7 +1382,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);
> {
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index aacf9b7251..35ded6d1d4 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -3825,9 +3825,11 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
> g_free(resv_prop_str);
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
> - uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
> - "cntfrq", &error_abort);
> - qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
> + if (!object_property_get_bool(OBJECT(dev), "wdat", &error_abort)) {
> + uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
> + "cntfrq", &error_abort);
> + qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
> + }
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
> if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
> error_setg(errp, "virt machine already has %s set. "
> @@ -3890,7 +3892,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
> sysbus_mmio_map(s, 1, cbase);
> sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
>
> - {
> + if (!object_property_get_bool(OBJECT(dev), "wdat", &error_abort)) {
> char *nodename = g_strdup_printf("/watchdog@%" PRIx64, cbase);
>
> qemu_fdt_add_subnode(ms->fdt, nodename);
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob
2026-06-24 10:28 ` [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
@ 2026-06-29 12:16 ` Eric Auger
0 siblings, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 12:16 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> 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..d5adacf9114637d8803d08906ff1e29ac61f5fe0 100644
> GIT binary patch
> literal 260
> zcmZXOK@NgI3`O4vF`x@byg*$Mjv=^kCkZBU9awQJZ&p(1B&bcAwm<K;ecx}dG(f1E
> zXZz@-8M;<PBmmZ16+lr{z~)btGhbi?GEanrk^*Op%cs@+r=JYk@zHbs;iGQ%_k0R#
> Y9+OSa{H}$nYB)I0_dnOT-}Sg>0T&h&0RR91
>
> literal 0
> HcmV?d00001
>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog
2026-06-29 8:37 ` Eric Auger
@ 2026-06-29 13:36 ` Igor Mammedov
2026-07-01 11:57 ` Eric Auger
0 siblings, 1 reply; 32+ messages in thread
From: Igor Mammedov @ 2026-06-29 13:36 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-devel, mst, peter.maydell, shannon.zhaosl, rad,
leif.lindholm, qemu-arm
On Mon, 29 Jun 2026 10:37:59 +0200
Eric Auger <eauger@redhat.com> wrote:
> Hi Igor,
>
> On 6/24/26 12:28 PM, Igor Mammedov wrote:
> > 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.
> >
> > Instead of using dynamic sysbus infra to wire up MMIO/IRQ/FDT,
> > statically assign resources in machine's mem/irq maps and wire
> > them up at device (pre_)plug handlers. It's similar to dynamic
> > sysbus wiring, modulo resources are nailed down statically,
> > and wiring is limited to virt machine only.
> > (Benefit is that tests don't break anymore on rebase due to
> > address being stable)
> >
> > Tested with Fedora 43:
> > FDT: -M virt,acpi=off -device sbsa-gwdt
> > ACPI: -M virt -device sbsa-gwdt
> >
> > Note:
> > Windows sees GTDT, initializes watchdog but instead pinging WRR
> > it sets/advances WOR to way too large value, so it's never going
> > to trigger watchdog reboot (it's Windows driver issue though).
> >
> > Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> > ---
> > v3:
> > - (Eric) assign MMIO/IRQ statically and abandon most of
> > dynamic sysbus machinery.
> > - (Peter) set watchdog freq to system clock explicitly,
> > machine version compat won't work in case host is not runing
> > 1GHz clock. (Tested on Jetson machine)
> > ---
> > include/hw/arm/virt.h | 3 +++
> > hw/arm/Kconfig | 1 +
> > hw/arm/virt-acpi-build.c | 29 +++++++++++++++++++++++++++--
> > hw/arm/virt.c | 37 +++++++++++++++++++++++++++++++++++++
> > hw/core/sysbus-fdt.c | 2 ++
> > hw/watchdog/sbsa_gwdt.c | 1 +
> > 6 files changed, 71 insertions(+), 2 deletions(-)
> >
[...]
> > @@ -3820,6 +3824,10 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> > qlist_append_str(reserved_regions, resv_prop_str);
> > qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
> > g_free(resv_prop_str);
> > + } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
> > + uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
> > + "cntfrq", &error_abort);
> missing extra line.
> > + qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
>
> Can you explain why you cannot do that in virt_machine_device_plug_cb()?
sure,
all prep work, typically is done at pre_plug time. (it's stage we are allowed to fail)
While at plug time we typically do final (post realize) wiring/exposing model to guest
(no allowed to fail (I need to do cleanup and remove errp from all plug handlers
but that is orthogonal to series))
> > } else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
> > if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
> > error_setg(errp, "virt machine already has %s set. "
[...]
> > 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";
> You may document somewhere that the device can be dynamically
> instantiated, in machvirt alone and this required machine specific
> hardwiring.
Any suggestion wrt where to put it?
>
> Thanks
>
> Eric
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition
2026-06-24 10:28 ` [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
@ 2026-06-29 14:03 ` Eric Auger
2026-06-29 14:51 ` Peter Maydell
1 sibling, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 14:03 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
Hi Igor,
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> No functional change, just code reorganization to
> prepare for direct WCV load support in the next commit.
>
> While at it, simplify timeout calculations
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> hw/watchdog/sbsa_gwdt.c | 16 ++++++----------
> 1 file changed, 6 insertions(+), 10 deletions(-)
>
> diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
> index 6113dcd077..5ee0e06af5 100644
> --- a/hw/watchdog/sbsa_gwdt.c
> +++ b/hw/watchdog/sbsa_gwdt.c
> @@ -109,22 +109,18 @@ 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)))) {
> + uint64_t offset = (uint64_t)s->woru << 32 | s->worl;
missing extra empty line (or is it no more requested?)
> + timeout = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> + muldiv64(offset, NANOSECONDS_PER_SECOND, s->freq);
> +
> /* store the current timeout value into compare registers */
> s->wcvu = timeout >> 32;
> s->wcvl = timeout;
> }
> +
> + timeout = (uint64_t)s->wcvu << 32 | s->wcvl;
> timer_mod(s->timer, timeout);
wouldn't it be simpler and functionally correct to call timer_del only
in case of !(s->wcs & SBSA_GWDT_WCS_EN) or actual refresh and let it
live otherwise?
Thanks
Eric
> }
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load
2026-06-24 10:28 ` [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load Igor Mammedov
@ 2026-06-29 14:08 ` Eric Auger
0 siblings, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 14:08 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> According to spec[1]:
>
> "The compare value can either be loaded directly or indirectly on an
> explicit refresh or timeout refresh"
>
> QEMU accepts writes to WCV but doesn't reschedule the timer,
> which it should per the spec pseudo code:
>
> "TimeoutRefresh = ( SystemCounter [63:0] > CompareValue [63:0])"
>
> Fix it by updating the timer on WCV write.
>
> Fixes Windows in GTDT mode, which never issues a WRR refresh.
> Instead, it programs WOR to ~4 sec, enables WCS, and immediately
> writes a large absolute value into WCV to push the timeout far
> into the future. Without this fix, QEMU ignores the WCV write,
> the short WOR expires, and the guest reboots unexpectedly.
>
> 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 | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
> index 5ee0e06af5..fb67db9672 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)
> @@ -167,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);
regarding my comment on previous patch, you could add a WCV_LOAD check
in sbsa_gwdt_update_timer now.
In the previous patch it is not obvious that the code is identical to
the original code in default path (hence my previous comment)
Eric
> + }
> break;
>
> case SBSA_GWDT_WCVU:
> s->wcvu = data;
> + if (s->wcs & SBSA_GWDT_WCS_EN) {
> + sbsa_gwdt_update_timer(s, WCV_LOAD);
> + }
> break;
>
> default:
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX
2026-06-24 10:28 ` [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX Igor Mammedov
@ 2026-06-29 14:10 ` Eric Auger
2026-06-29 14:48 ` Peter Maydell
1 sibling, 0 replies; 32+ messages in thread
From: Eric Auger @ 2026-06-29 14:10 UTC (permalink / raw)
To: Igor Mammedov, qemu-devel
Cc: mst, peter.maydell, shannon.zhaosl, rad, leif.lindholm, qemu-arm
On 6/24/26 12:28 PM, Igor Mammedov wrote:
> QEMU timer subsystem uses int64_t, so WCV values with bit 63 set
> overflow and cause the timer to fire immediately. The SBSA spec
> defines WCV as an unsigned 64-bit compare value, so such values
> are valid per spec and represent far-future deadlines (however
> unpractical).
>
> Windows in GTDT mode writes WCV in two 32-bit halves while the
> watchdog is running:
>
> sbsa-gwdt_control_write [0x8] <- 0xffffffff # WOR (~4 sec)
> sbsa-gwdt_control_write [0x0] <- 0x1 # WCS enable
> sbsa-gwdt_control_write [0x14] <- 0xffffffff # WCVU (intermediate)
> sbsa-gwdt_control_write [0x10] <- 0xa906ca28 # WCVL
> sbsa-gwdt_control_write [0x14] <- 0xecb1 # WCVU (final)
>
> The intermediate WCVU write (0xffffffff) creates a WCV above
> INT64_MAX, which overflows QEMU's signed timer and fires
> immediately — triggering WS0 => WS1 => reboot before the final
> WCVU write lands.
>
> Clamp WCV to INT64_MAX to avoid timer API overflow.
>
> Note: Windows' GTDT watchdog usage is also fragile under
> virtualization. It programs a short WOR (~4 sec), enables WCS,
> and relies on a subsequent WCV write to push the deadline far
> into the future — never using WRR for explicit refresh. On bare
> metal the WCS=>WCV gap is negligible, but in a VM the vCPU can
> be preempted between MMIO accesses while the clock keeps
> ticking, potentially expiring the short WOR timeout before the
> WCV override lands.
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> hw/watchdog/sbsa_gwdt.c | 2 ++
> tests/qtest/bios-tables-test.c | 2 +-
> 2 files changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
> index fb67db9672..ff7adbcb0f 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);
> }
>
> diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
> index 94fc95c8e1..370b0fd2e6 100644
> --- a/tests/qtest/bios-tables-test.c
> +++ b/tests/qtest/bios-tables-test.c
> @@ -2308,7 +2308,7 @@ static void test_acpi_aarch64_virt_tcg_gtdt_wd(void)
> .scan_len = 128ULL * MiB,
> };
>
> - test_acpi_one("-cpu cortex-a57 " "-device sbsa-gwdt", &data);
> + test_acpi_one("-cpu cortex-a57 -device sbsa-gwdt", &data);
looks unrelated to this patch.
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Besides
> free_test_data(&data);
> }
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX
2026-06-24 10:28 ` [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX Igor Mammedov
2026-06-29 14:10 ` Eric Auger
@ 2026-06-29 14:48 ` Peter Maydell
2026-06-30 12:14 ` Igor Mammedov
1 sibling, 1 reply; 32+ messages in thread
From: Peter Maydell @ 2026-06-29 14:48 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, eauger, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
On Wed, 24 Jun 2026 at 11:29, Igor Mammedov <imammedo@redhat.com> wrote:
>
> QEMU timer subsystem uses int64_t, so WCV values with bit 63 set
> overflow and cause the timer to fire immediately. The SBSA spec
> defines WCV as an unsigned 64-bit compare value, so such values
> are valid per spec and represent far-future deadlines (however
> unpractical).
>
> Windows in GTDT mode writes WCV in two 32-bit halves while the
> watchdog is running:
>
> sbsa-gwdt_control_write [0x8] <- 0xffffffff # WOR (~4 sec)
> sbsa-gwdt_control_write [0x0] <- 0x1 # WCS enable
> sbsa-gwdt_control_write [0x14] <- 0xffffffff # WCVU (intermediate)
> sbsa-gwdt_control_write [0x10] <- 0xa906ca28 # WCVL
> sbsa-gwdt_control_write [0x14] <- 0xecb1 # WCVU (final)
>
> The intermediate WCVU write (0xffffffff) creates a WCV above
> INT64_MAX, which overflows QEMU's signed timer and fires
> immediately — triggering WS0 => WS1 => reboot before the final
> WCVU write lands.
>
> Clamp WCV to INT64_MAX to avoid timer API overflow.
This bug doesn't exist as described in the current upstream
version of this device, because we don't use WCVU/WCVL in
calculating the timeout (only WORU/WORL, which are forced to
48 bits wide on write). This suggests that either you have
introduced it in this series, in which case it would be better
to not do that, or else that it exists in a different form
in current upstream, in which case it would be better to
fix it first in the patchset, so it can be cc:stable for
backports.
thanks
-- PMM
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition
2026-06-24 10:28 ` [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
2026-06-29 14:03 ` Eric Auger
@ 2026-06-29 14:51 ` Peter Maydell
1 sibling, 0 replies; 32+ messages in thread
From: Peter Maydell @ 2026-06-29 14:51 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, eauger, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
On Wed, 24 Jun 2026 at 11:29, Igor Mammedov <imammedo@redhat.com> wrote:
>
> No functional change, just code reorganization to
> prepare for direct WCV load support in the next commit.
>
> While at it, simplify timeout calculations
>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
> hw/watchdog/sbsa_gwdt.c | 16 ++++++----------
> 1 file changed, 6 insertions(+), 10 deletions(-)
>
> diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
> index 6113dcd077..5ee0e06af5 100644
> --- a/hw/watchdog/sbsa_gwdt.c
> +++ b/hw/watchdog/sbsa_gwdt.c
> @@ -109,22 +109,18 @@ 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)))) {
> + 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 the current timeout value into compare registers */
> s->wcvu = timeout >> 32;
> s->wcvl = timeout;
> }
> +
> + timeout = (uint64_t)s->wcvu << 32 | s->wcvl;
It is very unclear that this is a no-functional-change patch.
Previously we based the timeout on WORU/WORL. Now we are
basing it on WCVU/WCVL, which only in some cases are set to
a timeout value calculated from WORU/WORL.
This needs more explanation at minimum.
thanks
-- PMM
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX
2026-06-29 14:48 ` Peter Maydell
@ 2026-06-30 12:14 ` Igor Mammedov
0 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-06-30 12:14 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, mst, eauger, shannon.zhaosl, rad, leif.lindholm,
qemu-arm
On Mon, 29 Jun 2026 15:48:48 +0100
Peter Maydell <peter.maydell@linaro.org> wrote:
> On Wed, 24 Jun 2026 at 11:29, Igor Mammedov <imammedo@redhat.com> wrote:
> >
> > QEMU timer subsystem uses int64_t, so WCV values with bit 63 set
> > overflow and cause the timer to fire immediately. The SBSA spec
> > defines WCV as an unsigned 64-bit compare value, so such values
> > are valid per spec and represent far-future deadlines (however
> > unpractical).
> >
> > Windows in GTDT mode writes WCV in two 32-bit halves while the
> > watchdog is running:
> >
> > sbsa-gwdt_control_write [0x8] <- 0xffffffff # WOR (~4 sec)
> > sbsa-gwdt_control_write [0x0] <- 0x1 # WCS enable
> > sbsa-gwdt_control_write [0x14] <- 0xffffffff # WCVU (intermediate)
> > sbsa-gwdt_control_write [0x10] <- 0xa906ca28 # WCVL
> > sbsa-gwdt_control_write [0x14] <- 0xecb1 # WCVU (final)
> >
> > The intermediate WCVU write (0xffffffff) creates a WCV above
> > INT64_MAX, which overflows QEMU's signed timer and fires
> > immediately — triggering WS0 => WS1 => reboot before the final
> > WCVU write lands.
> >
> > Clamp WCV to INT64_MAX to avoid timer API overflow.
>
> This bug doesn't exist as described in the current upstream
> version of this device, because we don't use WCVU/WCVL in
> calculating the timeout (only WORU/WORL, which are forced to
> 48 bits wide on write). This suggests that either you have
> introduced it in this series, in which case it would be better
> to not do that, or else that it exists in a different form
> in current upstream, in which case it would be better to
> fix it first in the patchset, so it can be cc:stable for
> backports.
it's masked by missing timer reschedule on WCV update,
that preceding patch #16 fixes.
So yes it's ordering issue.
perhaps it's better split this patches into independed series,
given that the last 14-17 patches are fixing native GWDT
behavior for Windows usecase (which would still not work
due to too large timeouts)
and that it's not directly related to this series (linux uses
normal refresh approach with native gwdt mode), and WDAT mode
peddled by this series work fine with both Windows and Linux.
With the last 4 patches we still need to convince MS to fix large
timeouts on their side to make native gwdt work as expected.
>
> thanks
> -- PMM
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog
2026-06-29 13:36 ` Igor Mammedov
@ 2026-07-01 11:57 ` Eric Auger
2026-07-01 13:24 ` Igor Mammedov
0 siblings, 1 reply; 32+ messages in thread
From: Eric Auger @ 2026-07-01 11:57 UTC (permalink / raw)
To: Igor Mammedov
Cc: qemu-devel, mst, peter.maydell, shannon.zhaosl, rad,
leif.lindholm, qemu-arm
On 6/29/26 3:36 PM, Igor Mammedov wrote:
> On Mon, 29 Jun 2026 10:37:59 +0200
> Eric Auger <eauger@redhat.com> wrote:
>
>> Hi Igor,
>>
>> On 6/24/26 12:28 PM, Igor Mammedov wrote:
>>> 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.
>>>
>>> Instead of using dynamic sysbus infra to wire up MMIO/IRQ/FDT,
>>> statically assign resources in machine's mem/irq maps and wire
>>> them up at device (pre_)plug handlers. It's similar to dynamic
>>> sysbus wiring, modulo resources are nailed down statically,
>>> and wiring is limited to virt machine only.
>>> (Benefit is that tests don't break anymore on rebase due to
>>> address being stable)
>>>
>>> Tested with Fedora 43:
>>> FDT: -M virt,acpi=off -device sbsa-gwdt
>>> ACPI: -M virt -device sbsa-gwdt
>>>
>>> Note:
>>> Windows sees GTDT, initializes watchdog but instead pinging WRR
>>> it sets/advances WOR to way too large value, so it's never going
>>> to trigger watchdog reboot (it's Windows driver issue though).
>>>
>>> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
>>> ---
>>> v3:
>>> - (Eric) assign MMIO/IRQ statically and abandon most of
>>> dynamic sysbus machinery.
>>> - (Peter) set watchdog freq to system clock explicitly,
>>> machine version compat won't work in case host is not runing
>>> 1GHz clock. (Tested on Jetson machine)
>>> ---
>>> include/hw/arm/virt.h | 3 +++
>>> hw/arm/Kconfig | 1 +
>>> hw/arm/virt-acpi-build.c | 29 +++++++++++++++++++++++++++--
>>> hw/arm/virt.c | 37 +++++++++++++++++++++++++++++++++++++
>>> hw/core/sysbus-fdt.c | 2 ++
>>> hw/watchdog/sbsa_gwdt.c | 1 +
>>> 6 files changed, 71 insertions(+), 2 deletions(-)
>>>
> [...]
>>> @@ -3820,6 +3824,10 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
>>> qlist_append_str(reserved_regions, resv_prop_str);
>>> qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
>>> g_free(resv_prop_str);
>>> + } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
>>> + uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
>>> + "cntfrq", &error_abort);
>> missing extra line.
>>> + qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
>>
>> Can you explain why you cannot do that in virt_machine_device_plug_cb()?
>
> sure,
> all prep work, typically is done at pre_plug time. (it's stage we are allowed to fail)
>
> While at plug time we typically do final (post realize) wiring/exposing model to guest
> (no allowed to fail (I need to do cleanup and remove errp from all plug handlers
> but that is orthogonal to series))
>
>>> } else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
>>> if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
>>> error_setg(errp, "virt machine already has %s set. "
OK
> [...]
>
>>> 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";
>> You may document somewhere that the device can be dynamically
>> instantiated, in machvirt alone and this required machine specific
>> hardwiring.
>
> Any suggestion wrt where to put it?
At least you need to update system/arm/virt.rst with the new support of
the sbsa-gwdt device.
wrt the fact dt bindings are not created by default I would add least
add a comment above dc->user_creatable = true;
saying it requires manual dt bindings in the machine that uses it.
Thanks
Eric
>
>>
>> Thanks
>>
>> Eric
>>
>
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog
2026-07-01 11:57 ` Eric Auger
@ 2026-07-01 13:24 ` Igor Mammedov
0 siblings, 0 replies; 32+ messages in thread
From: Igor Mammedov @ 2026-07-01 13:24 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-devel, mst, peter.maydell, shannon.zhaosl, rad,
leif.lindholm, qemu-arm
On Wed, 1 Jul 2026 13:57:28 +0200
Eric Auger <eauger@redhat.com> wrote:
> On 6/29/26 3:36 PM, Igor Mammedov wrote:
> > On Mon, 29 Jun 2026 10:37:59 +0200
> > Eric Auger <eauger@redhat.com> wrote:
> >
> >> Hi Igor,
> >>
> >> On 6/24/26 12:28 PM, Igor Mammedov wrote:
> >>> 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.
> >>>
> >>> Instead of using dynamic sysbus infra to wire up MMIO/IRQ/FDT,
> >>> statically assign resources in machine's mem/irq maps and wire
> >>> them up at device (pre_)plug handlers. It's similar to dynamic
> >>> sysbus wiring, modulo resources are nailed down statically,
> >>> and wiring is limited to virt machine only.
> >>> (Benefit is that tests don't break anymore on rebase due to
> >>> address being stable)
> >>>
> >>> Tested with Fedora 43:
> >>> FDT: -M virt,acpi=off -device sbsa-gwdt
> >>> ACPI: -M virt -device sbsa-gwdt
> >>>
> >>> Note:
> >>> Windows sees GTDT, initializes watchdog but instead pinging WRR
> >>> it sets/advances WOR to way too large value, so it's never going
> >>> to trigger watchdog reboot (it's Windows driver issue though).
> >>>
> >>> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> >>> ---
> >>> v3:
> >>> - (Eric) assign MMIO/IRQ statically and abandon most of
> >>> dynamic sysbus machinery.
> >>> - (Peter) set watchdog freq to system clock explicitly,
> >>> machine version compat won't work in case host is not runing
> >>> 1GHz clock. (Tested on Jetson machine)
> >>> ---
> >>> include/hw/arm/virt.h | 3 +++
> >>> hw/arm/Kconfig | 1 +
> >>> hw/arm/virt-acpi-build.c | 29 +++++++++++++++++++++++++++--
> >>> hw/arm/virt.c | 37 +++++++++++++++++++++++++++++++++++++
> >>> hw/core/sysbus-fdt.c | 2 ++
> >>> hw/watchdog/sbsa_gwdt.c | 1 +
> >>> 6 files changed, 71 insertions(+), 2 deletions(-)
> >>>
> > [...]
> >>> @@ -3820,6 +3824,10 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> >>> qlist_append_str(reserved_regions, resv_prop_str);
> >>> qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
> >>> g_free(resv_prop_str);
> >>> + } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
> >>> + uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
> >>> + "cntfrq", &error_abort);
> >> missing extra line.
> >>> + qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
> >>
> >> Can you explain why you cannot do that in virt_machine_device_plug_cb()?
> >
> > sure,
> > all prep work, typically is done at pre_plug time. (it's stage we are allowed to fail)
> >
> > While at plug time we typically do final (post realize) wiring/exposing model to guest
> > (no allowed to fail (I need to do cleanup and remove errp from all plug handlers
> > but that is orthogonal to series))
> >
> >>> } else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
> >>> if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
> >>> error_setg(errp, "virt machine already has %s set. "
> OK
> > [...]
> >
> >>> 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";
> >> You may document somewhere that the device can be dynamically
> >> instantiated, in machvirt alone and this required machine specific
> >> hardwiring.
> >
> > Any suggestion wrt where to put it?
>
> At least you need to update system/arm/virt.rst with the new support of
> the sbsa-gwdt device.
done
> wrt the fact dt bindings are not created by default I would add least
> add a comment above dc->user_creatable = true;
> saying it requires manual dt bindings in the machine that uses it.
will do once I'm done with retesting,
I plan to respin today without last 4 patches.
They are basically independed fixes for native gwdt for windows
and are pre-existing issue (that would affect not only arm/virt but also current sbsa machine)
And then I'll spin off those 4 patches separately.
> Thanks
>
> Eric
>
> >
> >>
> >> Thanks
> >>
> >> Eric
> >>
> >
>
^ permalink raw reply [flat|nested] 32+ messages in thread
end of thread, other threads:[~2026-07-01 13:25 UTC | newest]
Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 01/17] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 02/17] arm: add tracing events to sbsa_gwdt Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt Igor Mammedov
2026-06-29 8:12 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog Igor Mammedov
2026-06-29 8:37 ` Eric Auger
2026-06-29 13:36 ` Igor Mammedov
2026-07-01 11:57 ` Eric Auger
2026-07-01 13:24 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 05/17] arm: sbsa-gwdt: add 'wdat' option Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 06/17] acpi: introduce WDAT table for GWDT Igor Mammedov
2026-06-29 12:07 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog Igor Mammedov
2026-06-29 12:15 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 08/17] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 09/17] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
2026-06-29 12:16 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 11/17] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 12/17] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 13/17] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 14/17] sbsa-gwdt: reduce code ident Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
2026-06-29 14:03 ` Eric Auger
2026-06-29 14:51 ` Peter Maydell
2026-06-24 10:28 ` [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load Igor Mammedov
2026-06-29 14:08 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX Igor Mammedov
2026-06-29 14:10 ` Eric Auger
2026-06-29 14:48 ` Peter Maydell
2026-06-30 12:14 ` Igor Mammedov
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.