From: Ashish Kalra <Ashish.Kalra@amd.com>
To: Borislav Petkov <bp@alien8.de>, Thomas Gleixner <tglx@kernel.org>,
"Ingo Molnar" <mingo@redhat.com>,
Dave Hansen <dave.hansen@linux.intel.com>, <x86@kernel.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>,
Tom Lendacky <thomas.lendacky@amd.com>,
Nikunj A Dadhania <nikunj@amd.com>,
Srikanth Aithal <Srikanth.Aithal@amd.com>, <kvm@vger.kernel.org>,
<linux-coco@lists.linux.dev>, <linux-kernel@vger.kernel.org>
Subject: [PATCH] x86/sev: Skip DR7 write during kexec when it would trigger an unserviceable #VC
Date: Fri, 21 Aug 2026 20:14:32 +0000 [thread overview]
Message-ID: <20260821201432.879450-1-Ashish.Kalra@amd.com> (raw)
From: Ashish Kalra <ashish.kalra@amd.com>
machine_kexec() calls hw_breakpoint_disable(), which writes DR7. On
SEV-ES/SNP guests that do not have DebugSwap enabled, DR7 accesses are
intercepted and delivered to the guest as a #VC exception, which must be
serviced through the GHCB.
By the time machine_kexec() runs, snp_kexec_finish() (called from
native_machine_shutdown()) has already converted the per-CPU GHCBs and
the boot GHCB back to private and set boot_ghcb to NULL, tearing down the
GHCB infrastructure. The DR7 write therefore raises a #VC that
dereferences a NULL GHCB pointer, causing a page fault and the kexec to
fail.
The NULL boot_ghcb pointer is a result of commit 3645eb7e3915 ("x86/fred:
Fix early boot failures on SEV-ES/SNP guests"): that change makes
__sev_get_ghcb() return the now-NULL boot_ghcb in this window, turning
the previously-benign teardown-window #VC (a bogus VMGEXIT the host
rejected but survived) into a NULL dereference.
Skip the DR7 write in this case. Its value is not needed across kexec
because the new kernel re-initializes DR7. Guests with DebugSwap enabled
context-switch DR7 in hardware and do not intercept the write, and
non-encrypted guests are unaffected, so both continue to call
hw_breakpoint_disable() as before.
Add a CC_ATTR_GUEST_DEBUG_VIRT confidential-computing attribute, so the
debug-register-virtualization state (AMD DebugSwap) is queried through
cc_platform_has().
Reported-by: Srikanth Aithal <Srikanth.Aithal@amd.com>
Suggested-by: Tom Lendacky <thomas.lendacky@amd.com>
Fixes: 3074152e56c9 ("x86/sev: Convert shared memory back to private on kexec")
Cc: stable@vger.kernel.org
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Reviewed-by: Nikunj A Dadhania <nikunj@amd.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Tested-by: Srikanth Aithal <Srikanth.Aithal@amd.com>
---
arch/x86/coco/core.c | 3 +++
arch/x86/kernel/machine_kexec_64.c | 11 ++++++++++-
include/linux/cc_platform.h | 8 ++++++++
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/x86/coco/core.c b/arch/x86/coco/core.c
index 989ca9f72ba3..d4c90a2da2bf 100644
--- a/arch/x86/coco/core.c
+++ b/arch/x86/coco/core.c
@@ -87,6 +87,9 @@ static bool noinstr amd_cc_platform_has(enum cc_attr attr)
case CC_ATTR_GUEST_STATE_ENCRYPT:
return sev_status & MSR_AMD64_SEV_ES_ENABLED;
+ case CC_ATTR_GUEST_DEBUG_VIRT:
+ return sev_status & MSR_AMD64_SNP_DEBUG_SWAP;
+
/*
* With SEV, the rep string I/O instructions need to be unrolled
* but SEV-ES supports them through the #VC handler.
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c
index c3f4a389992d..60d25ceada03 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -398,7 +398,16 @@ void __nocfi machine_kexec(struct kimage *image)
/* Interrupts aren't acceptable while we reboot */
local_irq_disable();
- hw_breakpoint_disable();
+
+ /*
+ * On SEV-ES/SEV-SNP guests without debug virtualization enabled, DR7
+ * writes are intercepted and generate a #VC. The GHCBs have already
+ * been torn down at this point so the #VC cannot be handled. Skip the
+ * DR7 write as the new kernel re-initializes DR7 during boot.
+ */
+ if (!cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT) ||
+ cc_platform_has(CC_ATTR_GUEST_DEBUG_VIRT))
+ hw_breakpoint_disable();
cet_disable();
if (image->preserve_context) {
diff --git a/include/linux/cc_platform.h b/include/linux/cc_platform.h
index 559353ad64ac..24ba1000ac94 100644
--- a/include/linux/cc_platform.h
+++ b/include/linux/cc_platform.h
@@ -62,6 +62,14 @@ enum cc_attr {
*/
CC_ATTR_GUEST_STATE_ENCRYPT,
+ /**
+ * @CC_ATTR_GUEST_DEBUG_VIRT: Guest debug register virtualization is active.
+ *
+ * The platform/OS is running as a guest/virtual machine and is
+ * virtualizing the debug register state.
+ */
+ CC_ATTR_GUEST_DEBUG_VIRT,
+
/**
* @CC_ATTR_GUEST_UNROLL_STRING_IO: String I/O is implemented with
* IN/OUT instructions
--
2.43.0
reply other threads:[~2026-08-21 20:15 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260821201432.879450-1-Ashish.Kalra@amd.com \
--to=ashish.kalra@amd.com \
--cc=Srikanth.Aithal@amd.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=nikunj@amd.com \
--cc=tglx@kernel.org \
--cc=thomas.lendacky@amd.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.