[PATCH v1 3/4] x86/vmware: Report guest crashes after kmsg dumpers
From: Zack Rusin
Date: Tue Sep 08 2026 - 14:47:13 EST
VMware accepts a structured guest-crash event, but a host configured with
backdoor.coredumpOnCrash may terminate the VM before the hypercall
returns. Sending the event from a panic notifier could prevent later kmsg
dumpers and a loaded crash kernel from running.
Register a second panic-only kmsg dumper with late_initcall_sync(). Kmsg
dumpers run in registration order, placing the report after the early
VMware logger and built-in dumpers registered by then. This leaves no
report before the late initcall, but avoids losing dump output to a
terminating host.
Skip the event when a crash kernel is loaded. The earlier logger can still
write panic text to vmware.log before __crash_kexec(). If kdump later
fails, no structured event is sent; issuing it first could prevent kdump
from running at all.
Issue the event at most once. With CONFIG_PRINTK=n, install a late
INT_MIN panic notifier. An unexpected dumper registration failure with
printk enabled leaves reporting disabled because a notifier fallback
would overtake working dumpers.
Link: https://lore.kernel.org/r/20260309235250.2611115-4-alexey.makhalov@xxxxxxxxxxxx
Co-developed-by: Brennan Lamoreaux <brennan.lamoreaux@xxxxxxxxxxxx>
Signed-off-by: Brennan Lamoreaux <brennan.lamoreaux@xxxxxxxxxxxx>
Co-developed-by: Alexey Makhalov <alexey.makhalov@xxxxxxxxxxxx>
Signed-off-by: Alexey Makhalov <alexey.makhalov@xxxxxxxxxxxx>
Signed-off-by: Zack Rusin <zack.rusin@xxxxxxxxxxxx>
---
arch/x86/include/asm/vmware.h | 1 +
arch/x86/kernel/cpu/vmware.c | 63 +++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+)
diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
index 598d4cd448ec..ea2ce5272a00 100644
--- a/arch/x86/include/asm/vmware.h
+++ b/arch/x86/include/asm/vmware.h
@@ -61,6 +61,7 @@
#define VMWARE_CMD_GETHZ 45
#define VMWARE_CMD_GETVCPU_INFO 68
#define VMWARE_CMD_STEALCLOCK 91
+#define VMWARE_CMD_REPORTGUESTCRASH 102
/*
* Hypercall command mask:
* bits [6:0] command, range [0, 127]
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 3848811550e9..c21fc835537f 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -22,10 +22,14 @@
*/
#include <linux/dmi.h>
+#include <linux/atomic.h>
+#include <linux/crash_core.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/kmsg_dump.h>
+#include <linux/limits.h>
#include <linux/mm.h>
+#include <linux/panic_notifier.h>
#include <linux/clocksource.h>
#include <linux/cpu.h>
#include <linux/efi.h>
@@ -323,6 +327,65 @@ static int __init vmware_panic_log_init(void)
}
early_initcall(vmware_panic_log_init);
+static atomic_t vmware_crash_reported = ATOMIC_INIT(0);
+
+static void vmware_report_guest_crash(void)
+{
+ if (kexec_crash_loaded())
+ return;
+ if (atomic_xchg(&vmware_crash_reported, 1))
+ return;
+
+ vmware_hypercall1(VMWARE_CMD_REPORTGUESTCRASH, 0);
+}
+
+static void vmware_crash_report_dump(struct kmsg_dumper *dumper,
+ struct kmsg_dump_detail *detail)
+{
+ vmware_report_guest_crash();
+}
+
+static struct kmsg_dumper vmware_crash_report_dumper = {
+ .dump = vmware_crash_report_dump,
+ .max_reason = KMSG_DUMP_PANIC,
+};
+
+static int vmware_crash_report_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ vmware_report_guest_crash();
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block vmware_crash_report_nb = {
+ .notifier_call = vmware_crash_report_notify,
+ .priority = INT_MIN,
+};
+
+static int __init vmware_crash_report_init(void)
+{
+ int ret;
+
+ if (!hypervisor_is_type(X86_HYPER_VMWARE))
+ return 0;
+
+ ret = kmsg_dump_register(&vmware_crash_report_dumper);
+ if (!ret)
+ return 0;
+ if (IS_ENABLED(CONFIG_PRINTK)) {
+ pr_err("failed to register crash report dumper: %d\n", ret);
+ return 0;
+ }
+
+ ret = atomic_notifier_chain_register(&panic_notifier_list,
+ &vmware_crash_report_nb);
+ if (ret)
+ pr_err("failed to register crash report notifier: %d\n", ret);
+
+ return 0;
+}
+late_initcall_sync(vmware_crash_report_init);
+
#ifdef CONFIG_PARAVIRT
static struct cyc2ns_data vmware_cyc2ns __ro_after_init;
static bool vmw_sched_clock __initdata = true;
--
2.53.0