* [PATCH v2] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized [not found] <20261029080731.890996-1-challvy.tee@gmail.com> @ 2026-10-29 9:47 ` Challvy Tee 2026-10-29 12:10 ` Kiryl Shutsemau 0 siblings, 1 reply; 5+ messages in thread From: Challvy Tee @ 2026-10-29 9:47 UTC (permalink / raw) To: x86, linux-coco Cc: linux-kernel, regressions, dave.hansen, kas, rick.p.edgecombe, vishal.l.verma, kai.huang, Challvy Tee, stable Commit 5b25f249be32 ("x86/tdx: Disable the TDX module during kexec and kdump") made native_machine_crash_shutdown() call tdx_sys_disable(), but tdx_sys_disable() has no runtime gate: its only guard is compile time (CONFIG_INTEL_TDX_HOST), which is enabled in most kernel configs. On a system where the TDX module was never initialized, kdump now issues a TDH.SYS.DISABLE SEAMCALL that it did not issue before, and the crash path never reaches machine_kexec(). The capture kernel is never entered and no vmcore is written, so kdump is completely non-functional. Having the TDX module uninitialized is an ordinary state rather than an error. tdx_enable() returns -ENODEV early when X86_FEATURE_TDX_HOST_PLATFORM is absent, and it also bails out if init_tdx_module() fails. Any guest whose host does not expose TDX is in this state and logs: virt/tdx: TDX not supported by the host platform The syscore path is implicitly protected: register_syscore() only runs after init_tdx_module() succeeds, so tdx_shutdown() cannot be reached on an uninitialized system. That is why plain kexec still works and only kdump regressed. The crash path calls tdx_sys_disable() directly and bypasses that protection. Reproduced with 'echo c > /proc/sysrq-trigger' in VM guests on Intel Sapphire Rapids, Emerald Rapids and Granite Rapids platforms, in every case on a kernel that already contains the change described above: the capture kernel is never entered and no vmcore is produced. With this patch applied kdump completes normally on all of them. Three negative controls, all of which produce a vmcore as expected: the same guests on kernels without that change, guests on platforms without SEAM support, and plain kexec on every platform tested. On a host where the module did initialize the new gate is a no-op and TDH.SYS.DISABLE is still issued, so the poison clearing that the above commit was added for is unaffected. We do not have a TDX host to test on, so this part is reasoned from the code rather than measured. Gate the SEAMCALL on tdx_module_state.initialized, the same predicate tdx_get_sysinfo() already uses in this file. Putting the check inside tdx_sys_disable() rather than at the crash.c call site also covers the syscore caller and any future caller. Fixes: 5b25f249be32 ("x86/tdx: Disable the TDX module during kexec and kdump") Cc: stable@vger.kernel.org Signed-off-by: Challvy Tee <challvy.tee@gmail.com> --- v1 -> v2: - Use the real commit id 5b25f249be32 in the Fixes: tag and in the opening paragraph; v1 went out with a placeholder instead. - Drop the claim that nothing reaches the console. panic() prints the message and backtrace before __crash_kexec(), so they do appear; describe the failure as the crash path never reaching machine_kexec() instead. - Drop the paragraph that explained why guests on platforms without SEAM support are unaffected. It asserted a mechanism we have not verified, and the negative controls now carry the same information. - State explicitly that a host where the module did initialize is unaffected, so the poison clearing the fixed commit was added for still happens, and say plainly that we have no TDX host to test on. - Restrict the syscore claim to kexec: tdx_suspend() does not call tdx_sys_disable(). - Resend with the full get_maintainer.pl recipient list. v1 only reached stable@ and missed LKML and the x86 maintainers entirely. v1: https://lore.kernel.org/all/20261029080731.890996-1-challvy.tee@gmail.com/ - No code change. arch/x86/virt/vmx/tdx/tdx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 96ced0494b68..a7eae7492c1e 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -2321,6 +2321,9 @@ void tdx_sys_disable(void) struct tdx_module_args args = {}; u64 ret; + if (!tdx_module_state.initialized) + return; + /* * Don't loop forever. * -- 2.52.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized 2026-10-29 9:47 ` [PATCH v2] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized Challvy Tee @ 2026-10-29 12:10 ` Kiryl Shutsemau 2026-10-30 15:48 ` [PATCH v3] " Challvy Tee 0 siblings, 1 reply; 5+ messages in thread From: Kiryl Shutsemau @ 2026-10-29 12:10 UTC (permalink / raw) To: Challvy Tee Cc: x86, linux-coco, linux-kernel, regressions, dave.hansen, rick.p.edgecombe, vishal.l.verma, kai.huang, stable On Thu, Oct 29, 2026 at 05:47:05PM +0800, Challvy Tee wrote: > Commit 5b25f249be32 ("x86/tdx: Disable the TDX module during kexec and > kdump") made native_machine_crash_shutdown() call tdx_sys_disable(), but > tdx_sys_disable() has no runtime gate: its only guard is compile time > (CONFIG_INTEL_TDX_HOST), which is enabled in most kernel configs. On a > system where the TDX module was never initialized, kdump now issues a > TDH.SYS.DISABLE SEAMCALL that it did not issue before, and the crash > path never reaches machine_kexec(). The capture kernel is never entered > and no vmcore is written, so kdump is completely non-functional. > > Having the TDX module uninitialized is an ordinary state rather than an > error. tdx_enable() returns -ENODEV early when > X86_FEATURE_TDX_HOST_PLATFORM is absent, and it also bails out if > init_tdx_module() fails. Any guest whose host does not expose TDX is in > this state and logs: > > virt/tdx: TDX not supported by the host platform > > The syscore path is implicitly protected: register_syscore() only runs > after init_tdx_module() succeeds, so tdx_shutdown() cannot be reached on > an uninitialized system. That is why plain kexec still works and only > kdump regressed. > > The crash path calls tdx_sys_disable() directly and bypasses that > protection. > > Reproduced with 'echo c > /proc/sysrq-trigger' in VM guests on Intel > Sapphire Rapids, Emerald Rapids and Granite Rapids platforms, in every > case on a kernel that already contains the change described above: the > capture kernel is never entered and no vmcore is produced. With this > patch applied kdump completes normally on all of them. > > Three negative controls, all of which produce a vmcore as expected: the > same guests on kernels without that change, guests on platforms without > SEAM support, and plain kexec on every platform tested. > > On a host where the module did initialize the new gate is a no-op and > TDH.SYS.DISABLE is still issued, so the poison clearing that the above > commit was added for is unaffected. We do not have a TDX host to test > on, so this part is reasoned from the code rather than measured. > > Gate the SEAMCALL on tdx_module_state.initialized, the same predicate > tdx_get_sysinfo() already uses in this file. Putting the check inside > tdx_sys_disable() rather than at the crash.c call site also covers the > syscore caller and any future caller. > > Fixes: 5b25f249be32 ("x86/tdx: Disable the TDX module during kexec and kdump") > Cc: stable@vger.kernel.org > Signed-off-by: Challvy Tee <challvy.tee@gmail.com> The changelog is long for a three-line check, and it doesn't say why the crash path stops. It takes time to understand what you try to fix. A SEAMCALL that hits #UD is caught by the fixup in tdxcall.S and returns TDX_SEAMCALL_UD; tdx_sys_disable() then leaves the loop without printing anything. That is your no-SEAM control, and kdump works there. On SPR and later, SEAMCALL in VMX non-root causes a VM exit instead, and what happens next is up to the hypervisor. KVM injects #UD only since 9d7dfb95da2c ("KVM: VMX: Inject #UD if guest tries to execute SEAMCALL or TDCALL"); before that it is an unexpected exit reason and the VMM gets KVM_EXIT_INTERNAL_ERROR. What hypervisor are your guests running on? Does the host log "unexpected exit reason 0x4c"? If that is it, kdump is broken only in guests on SEAM-capable hosts whose hypervisor doesn't handle the exit. The changelog should say so in a couple of paragraphs. -- Kiryl Shutsemau / Kirill A. Shutemov ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized 2026-10-29 12:10 ` Kiryl Shutsemau @ 2026-10-30 15:48 ` Challvy Tee 2026-10-30 16:13 ` Dave Hansen 0 siblings, 1 reply; 5+ messages in thread From: Challvy Tee @ 2026-10-30 15:48 UTC (permalink / raw) To: x86, linux-coco Cc: linux-kernel, kvm, regressions, stable, kas, dave.hansen, rick.p.edgecombe, vishal.l.verma, kai.huang, seanjc Commit 5b25f249be32 ("x86/tdx: Disable the TDX module during kexec and kdump") made native_machine_crash_shutdown() call tdx_sys_disable(), whose only gate is compile time (CONFIG_INTEL_TDX_HOST). A kernel that never initialized the TDX module therefore still issues TDH.SYS.DISABLE. In VMX non-root operation on a SEAM-capable host, SEAMCALL causes a VM exit instead of a native #UD. KVM injects #UD only since commit 9d7dfb95da2c ("KVM: VMX: Inject #UD if guest tries to execute SEAMCALL or TDCALL"), first released in v6.18. On an older host the VMM gets KVM_EXIT_INTERNAL_ERROR and the vCPU never resumes, so machine_kexec() is never reached and no vmcore is written. Kdump is thus broken only in guests on SEAM-capable hosts whose hypervisor does not handle the exit; plain kexec is unaffected because tdx_shutdown() only runs as a syscore op, registered after init_tdx_module() succeeds. Gate the SEAMCALL on tdx_module_state.initialized, the predicate tdx_get_sysinfo() already uses in this file: a kernel that never initialized the module has no module to disable, and where it did the gate is a no-op. Doing it here rather than at the crash.c call site also covers the syscore caller and any future one. It also decouples kdump from the host KVM version -- a guest cannot require its host to inject the #UD. Fixes: 5b25f249be32 ("x86/tdx: Disable the TDX module during kexec and kdump") Cc: stable@vger.kernel.org Signed-off-by: Challvy Tee <challvy.tee@gmail.com> --- v2 -> v3: - Rework the changelog around the VM exit mechanism from the review and scope the impact to guests on SEAM-capable hosts whose hypervisor does not handle the exit. - Shorten it and move the reproduction data below the fold. - Cc the author of the KVM commit now cited. No code change. v2: https://lore.kernel.org/all/20261029094705.896693-1-challvy.tee@gmail.com/ Hypervisor -- KVM on all five (CPUID leaf 0x40000000), across three clouds: Alibaba Cloud ECS, AWS EC2 and Tencent Cloud CVM. Host log -- yes, from the Alibaba ECS host of the Emerald Rapids guest: KVM internal error. Suberror: 4 extra data[0]: 4c extra data[1]: 2f RAX=0000000000000045 RDI=0000000000000045 RIP=ffffffff855422fe R12=8000020300000000 R13=8000000300000000 R14=8000020200000000 Code=... 4c 8b 5e 28 <66> 0f 01 cf 72 05 ... check runstate transition: 'running' -> 'internal-error' Suberror 4 is KVM_INTERNAL_ERROR_UNEXPECTED_EXIT_REASON; the two data words are the exit reason (0x4c = EXIT_REASON_SEAMCALL) and last_vmentry_cpu, i.e. kvm_prepare_unexpected_reason_exit(). RAX and RDI hold 0x45 = TDH_SYS_DISABLE and RIP is at the '66 0f 01 cf' SEAMCALL opcode in __seamcall. RAX still holds the input leaf rather than a status code: the SEAMCALL never returned. Reproduced with 'echo c > /proc/sysrq-trigger'. All five have CONFIG_INTEL_TDX_HOST=y, kexec_crash_loaded=1, a kernel changelog naming both backported commits, and "TDX not supported by the host platform" in dmesg: Microarch x86_vfm Cloud Kernel echo c Sapphire Rapids 0x68F AWS EC2 6.12.0-278.el10 no vmcore Emerald Rapids 0x6CF Alibaba ECS 6.12.0-278.el10 no vmcore Granite Rapids 0x6AD Alibaba ECS 6.12.0-278.el10 no vmcore Granite Rapids 0x6AD AWS EC2 6.12.0-278.el10 no vmcore Granite Rapids 0x6AD Tencent CVM 6.12.0-278.el10 no vmcore Controls, each producing a vmcore: the same platform on a kernel without 5b25f249be32 (tdx_sys_disable absent from kallsyms), platforms without SEAM support (Skylake, Cascade Lake, Ice Lake, AMD), and plain kexec. With the gate applied kdump produces a vmcore on the two Alibaba ECS guests; the others have not been retested. No TDX host was available, so the no-op case is reasoned from the code rather than measured. arch/x86/virt/vmx/tdx/tdx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 96ced0494b68..a7eae7492c1e 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -2321,6 +2321,9 @@ void tdx_sys_disable(void) struct tdx_module_args args = {}; u64 ret; + if (!tdx_module_state.initialized) + return; + /* * Don't loop forever. * -- 2.52.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized 2026-10-30 15:48 ` [PATCH v3] " Challvy Tee @ 2026-10-30 16:13 ` Dave Hansen 2026-10-30 16:26 ` Kiryl Shutsemau 0 siblings, 1 reply; 5+ messages in thread From: Dave Hansen @ 2026-10-30 16:13 UTC (permalink / raw) To: Challvy Tee, x86, linux-coco Cc: linux-kernel, kvm, regressions, stable, kas, dave.hansen, rick.p.edgecombe, vishal.l.verma, kai.huang, seanjc On 10/30/26 08:48, Challvy Tee wrote: > --- a/arch/x86/virt/vmx/tdx/tdx.c > +++ b/arch/x86/virt/vmx/tdx/tdx.c > @@ -2321,6 +2321,9 @@ void tdx_sys_disable(void) > struct tdx_module_args args = {}; > u64 ret; > > + if (!tdx_module_state.initialized) > + return; NAK from me on this. If SEAMCALL is fatal then we need stronger barriers on the generic paths to SEAMCALLs themselves, not one-off patches of the sites. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized 2026-10-30 16:13 ` Dave Hansen @ 2026-10-30 16:26 ` Kiryl Shutsemau 0 siblings, 0 replies; 5+ messages in thread From: Kiryl Shutsemau @ 2026-10-30 16:26 UTC (permalink / raw) To: Dave Hansen Cc: Challvy Tee, x86, linux-coco, linux-kernel, kvm, regressions, stable, dave.hansen, rick.p.edgecombe, vishal.l.verma, kai.huang, seanjc On Fri, Oct 30, 2026 at 09:13:12AM -0700, Dave Hansen wrote: > On 10/30/26 08:48, Challvy Tee wrote: > > --- a/arch/x86/virt/vmx/tdx/tdx.c > > +++ b/arch/x86/virt/vmx/tdx/tdx.c > > @@ -2321,6 +2321,9 @@ void tdx_sys_disable(void) > > struct tdx_module_args args = {}; > > u64 ret; > > > > + if (!tdx_module_state.initialized) > > + return; > > NAK from me on this. > > If SEAMCALL is fatal then we need stronger barriers on the generic paths > to SEAMCALLs themselves, not one-off patches of the sites. I don't think the generic path is the right place for it. For every other caller, reaching a SEAMCALL on a non-TDX system means something went wrong higher up, and we want to see it. A check there that quietly returns an error hides that. Making it WARN would catch it, but then the crash path would still need its own check before the call. So gate the call on X86_FEATURE_TDX_HOST_PLATFORM, the same way paddr_is_tdx_private() does. -- Kiryl Shutsemau / Kirill A. Shutemov ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-30 16:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20261029080731.890996-1-challvy.tee@gmail.com>
2026-10-29 9:47 ` [PATCH v2] x86/virt/tdx: Skip TDH.SYS.DISABLE if the TDX module is not initialized Challvy Tee
2026-10-29 12:10 ` Kiryl Shutsemau
2026-10-30 15:48 ` [PATCH v3] " Challvy Tee
2026-10-30 16:13 ` Dave Hansen
2026-10-30 16:26 ` Kiryl Shutsemau
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.