]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/tdx: Fix arch_safe_halt() execution for TDX VMs
authorVishal Annapurve <vannapurve@google.com>
Fri, 28 Feb 2025 01:44:15 +0000 (01:44 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Apr 2025 12:39:37 +0000 (14:39 +0200)
commit 9f98a4f4e7216dbe366010b4cdcab6b220f229c4 upstream.

Direct HLT instruction execution causes #VEs for TDX VMs which is routed
to hypervisor via TDCALL. If HLT is executed in STI-shadow, resulting #VE
handler will enable interrupts before TDCALL is routed to hypervisor
leading to missed wakeup events, as current TDX spec doesn't expose
interruptibility state information to allow #VE handler to selectively
enable interrupts.

Commit bfe6ed0c6727 ("x86/tdx: Add HLT support for TDX guests")
prevented the idle routines from executing HLT instruction in STI-shadow.
But it missed the paravirt routine which can be reached via this path
as an example:

kvm_wait()       =>
        safe_halt()      =>
        raw_safe_halt()  =>
        arch_safe_halt() =>
        irq.safe_halt()  =>
        pv_native_safe_halt()

To reliably handle arch_safe_halt() for TDX VMs, introduce explicit
dependency on CONFIG_PARAVIRT and override paravirt halt()/safe_halt()
routines with TDX-safe versions that execute direct TDCALL and needed
interrupt flag updates. Executing direct TDCALL brings in additional
benefit of avoiding HLT related #VEs altogether.

As tested by Ryan Afranji:

  "Tested with the specjbb2015 benchmark. It has heavy lock contention which leads
   to many halt calls. TDX VMs suffered a poor score before this patchset.

   Verified the major performance improvement with this patchset applied."

Fixes: bfe6ed0c6727 ("x86/tdx: Add HLT support for TDX guests")
Signed-off-by: Vishal Annapurve <vannapurve@google.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Tested-by: Ryan Afranji <afranji@google.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20250228014416.3925664-3-vannapurve@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/Kconfig
arch/x86/coco/tdx/tdx.c
arch/x86/include/asm/tdx.h
arch/x86/kernel/process.c

index c915097d3b73293033c9f5132330a5431cc5b39b..db38d2b9b7886831ac4378e408db26b030de6964 100644 (file)
@@ -894,6 +894,7 @@ config INTEL_TDX_GUEST
        depends on X86_64 && CPU_SUP_INTEL
        depends on X86_X2APIC
        depends on EFI_STUB
+       depends on PARAVIRT
        select ARCH_HAS_CC_PLATFORM
        select X86_MEM_ENCRYPT
        select X86_MCE
index 2f85ed005c42f17b71fc9f7ae0c4f387ba342f3e..b8aeb3ac7d28b798058b7c858ccb8573a167a8cf 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/ia32.h>
 #include <asm/insn.h>
 #include <asm/insn-eval.h>
+#include <asm/paravirt_types.h>
 #include <asm/pgtable.h>
 #include <asm/set_memory.h>
 #include <asm/traps.h>
@@ -359,7 +360,7 @@ static int handle_halt(struct ve_info *ve)
        return ve_instr_len(ve);
 }
 
-void __cpuidle tdx_safe_halt(void)
+void __cpuidle tdx_halt(void)
 {
        const bool irq_disabled = false;
 
@@ -370,6 +371,16 @@ void __cpuidle tdx_safe_halt(void)
                WARN_ONCE(1, "HLT instruction emulation failed\n");
 }
 
+static void __cpuidle tdx_safe_halt(void)
+{
+       tdx_halt();
+       /*
+        * "__cpuidle" section doesn't support instrumentation, so stick
+        * with raw_* variant that avoids tracing hooks.
+        */
+       raw_local_irq_enable();
+}
+
 static int read_msr(struct pt_regs *regs, struct ve_info *ve)
 {
        struct tdx_module_args args = {
@@ -1056,6 +1067,19 @@ void __init tdx_early_init(void)
        x86_platform.guest.enc_kexec_begin           = tdx_kexec_begin;
        x86_platform.guest.enc_kexec_finish          = tdx_kexec_finish;
 
+       /*
+        * Avoid "sti;hlt" execution in TDX guests as HLT induces a #VE that
+        * will enable interrupts before HLT TDCALL invocation if executed
+        * in STI-shadow, possibly resulting in missed wakeup events.
+        *
+        * Modify all possible HLT execution paths to use TDX specific routines
+        * that directly execute TDCALL and toggle the interrupt state as
+        * needed after TDCALL completion. This also reduces HLT related #VEs
+        * in addition to having a reliable halt logic execution.
+        */
+       pv_ops.irq.safe_halt = tdx_safe_halt;
+       pv_ops.irq.halt = tdx_halt;
+
        /*
         * TDX intercepts the RDMSR to read the X2APIC ID in the parallel
         * bringup low level code. That raises #VE which cannot be handled
index eba178996d8459b2ead1800e83157346f9c50c04..b5b633294061375c8f1f5f001cf483afa4b9f070 100644 (file)
@@ -58,7 +58,7 @@ void tdx_get_ve_info(struct ve_info *ve);
 
 bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve);
 
-void tdx_safe_halt(void);
+void tdx_halt(void);
 
 bool tdx_early_handle_ve(struct pt_regs *regs);
 
@@ -69,7 +69,7 @@ u64 tdx_hcall_get_quote(u8 *buf, size_t size);
 #else
 
 static inline void tdx_early_init(void) { };
-static inline void tdx_safe_halt(void) { };
+static inline void tdx_halt(void) { };
 
 static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; }
 
index e42db0de02920e5a2c8f371be14be21a1ae455ee..c7ce3655b70780ce965c7b912d884ac07d38bc62 100644 (file)
@@ -938,7 +938,7 @@ void __init select_idle_routine(void)
                static_call_update(x86_idle, mwait_idle);
        } else if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) {
                pr_info("using TDX aware idle routine\n");
-               static_call_update(x86_idle, tdx_safe_halt);
+               static_call_update(x86_idle, tdx_halt);
        } else {
                static_call_update(x86_idle, default_idle);
        }