From nobody Sat Feb 7 08:28:03 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7FE9C2E06EA; Fri, 23 Jan 2026 15:00:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769180416; cv=none; b=SBgSYFX5pnUuCoZYtxFO31609lF5yDUMHhF5OEX+yPWEmULju2Ohib9Q2Soh0/OutOqgKc7DosjKcDONbXj9j8nfvq/q6XrgR7d5cUOlC2voL8iZBSDPt0Ra7Tzo8m2rOk7XlZolNi4FkuQ0xgwIIekEe9yr8nmoxVm+aqZtOdk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769180416; c=relaxed/simple; bh=i+mes0H/CJ0dnn+DCy/4MLZXFZzfpvSzV38ZMOA56jg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CWN+Z0WUPkekjhEvjnQNXx5k8m3eT8MgfTD/iWE++05Ppp14gNWK2unyOxfApqkm/NmK68B39QiRMKpRvoTNCrilIJzJjWPDlxyEAevkay/BBh/1AeCaNBVmOWtqcEBvCyT4d7MdCWbOxGZDLgjFC2LnmM9WvmDz9PUgekFj6Ps= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=m+mg+C99; arc=none smtp.client-ip=192.198.163.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="m+mg+C99" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1769180414; x=1800716414; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=i+mes0H/CJ0dnn+DCy/4MLZXFZzfpvSzV38ZMOA56jg=; b=m+mg+C99i2GiNC3BE7dzgTnenk/6MwsDmW502qoFsQerW8kdLCw4jy1m ZYCXd+IMalEtmy7vH1OL1kx9izvOrId1pRIBc+QId7W0Gdb2Sya/uUjP1 yhB3TEOOhtk2JLLssT8rdh2KT+WojaG8XSPcp5HgZSqp1W/w0Vn68eJzH rB2RvcjkGCIxoqD22HsQkZWCqcm6tVtdQtWD2Owi0hyz6+ykTl8VFxvWk kLznLCLlAgutavL/r67b3IUsGvIrhneqhsLy0D4CySCdEsZ9kz0Kokf6Y kS4bv7oG9+QZdYns6PzIA3j0vObT4lcThbaD+jyLO9fWBCzPDaQCEWbmZ g==; X-CSE-ConnectionGUID: go8UfU0uRN+APxzJuuAlkA== X-CSE-MsgGUID: 1aVBnQrQTxWYfU2tP0xCeQ== X-IronPort-AV: E=McAfee;i="6800,10657,11680"; a="70334346" X-IronPort-AV: E=Sophos;i="6.21,248,1763452800"; d="scan'208";a="70334346" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by fmvoesa111.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2026 07:00:09 -0800 X-CSE-ConnectionGUID: H1GVEiG/RR+ehrVmie6vdw== X-CSE-MsgGUID: Oa4k5bQ1QzC44KRB851/TQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,248,1763452800"; d="scan'208";a="237697043" Received: from 984fee019967.jf.intel.com ([10.23.153.244]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jan 2026 07:00:08 -0800 From: Chao Gao To: linux-coco@lists.linux.dev, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, x86@kernel.org Cc: reinette.chatre@intel.com, ira.weiny@intel.com, kai.huang@intel.com, dan.j.williams@intel.com, yilun.xu@linux.intel.com, sagis@google.com, vannapurve@google.com, paulmck@kernel.org, nik.borisov@suse.com, zhenzhong.duan@intel.com, seanjc@google.com, rick.p.edgecombe@intel.com, kas@kernel.org, dave.hansen@linux.intel.com, vishal.l.verma@intel.com, Chao Gao , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" Subject: [PATCH v3 03/26] x86/virt/tdx: Move low level SEAMCALL helpers out of Date: Fri, 23 Jan 2026 06:55:11 -0800 Message-ID: <20260123145645.90444-4-chao.gao@intel.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com> References: <20260123145645.90444-1-chao.gao@intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kai Huang TDX host core code implements three seamcall*() helpers to make SEAMCALL to the TDX module. Currently, they are implemented in and are exposed to other kernel code which includes . However, other than the TDX host core, seamcall*() are not expected to be used by other kernel code directly. For instance, for all SEAMCALLs that are used by KVM, the TDX host core exports a wrapper function for each of them. Move seamcall*() and related code out of and make them only visible to TDX host core. Since TDX host core tdx.c is already very heavy, don't put low level seamcall*() code there but to a new dedicated "seamcall.h". Also, currently tdx.c has seamcall_prerr*() helpers which additionally print error message when calling seamcall*() fails. Move them to "seamcall.h" as well. In such way all low level SEAMCALL helpers are in a dedicated place, which is much more readable. Signed-off-by: Kai Huang Signed-off-by: Chao Gao Reviewed-by: Zhenzhong Duan Acked-by: Dave Hansen Reviewed-by: Binbin Wu Reviewed-by: Tony Lindgren --- v2: - new --- arch/x86/include/asm/tdx.h | 47 --------------- arch/x86/virt/vmx/tdx/seamcall.h | 99 ++++++++++++++++++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.c | 46 +-------------- 3 files changed, 100 insertions(+), 92 deletions(-) create mode 100644 arch/x86/virt/vmx/tdx/seamcall.h diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 6b338d7f01b7..cb2219302dfc 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -97,54 +97,7 @@ static inline long tdx_kvm_hypercall(unsigned int nr, un= signed long p1, #endif /* CONFIG_INTEL_TDX_GUEST && CONFIG_KVM_GUEST */ =20 #ifdef CONFIG_INTEL_TDX_HOST -u64 __seamcall(u64 fn, struct tdx_module_args *args); -u64 __seamcall_ret(u64 fn, struct tdx_module_args *args); -u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args); void tdx_init(void); - -#include -#include -#include - -typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args); - -static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn, - struct tdx_module_args *args) -{ - lockdep_assert_preemption_disabled(); - - /* - * SEAMCALLs are made to the TDX module and can generate dirty - * cachelines of TDX private memory. Mark cache state incoherent - * so that the cache can be flushed during kexec. - * - * This needs to be done before actually making the SEAMCALL, - * because kexec-ing CPU could send NMI to stop remote CPUs, - * in which case even disabling IRQ won't help here. - */ - this_cpu_write(cache_state_incoherent, true); - - return func(fn, args); -} - -static __always_inline u64 sc_retry(sc_func_t func, u64 fn, - struct tdx_module_args *args) -{ - int retry =3D RDRAND_RETRY_LOOPS; - u64 ret; - - do { - preempt_disable(); - ret =3D __seamcall_dirty_cache(func, fn, args); - preempt_enable(); - } while (ret =3D=3D TDX_RND_NO_ENTROPY && --retry); - - return ret; -} - -#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args)) -#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args)) -#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn= ), (_args)) int tdx_cpu_enable(void); int tdx_enable(void); const char *tdx_dump_mce_info(struct mce *m); diff --git a/arch/x86/virt/vmx/tdx/seamcall.h b/arch/x86/virt/vmx/tdx/seamc= all.h new file mode 100644 index 000000000000..0912e03fabfe --- /dev/null +++ b/arch/x86/virt/vmx/tdx/seamcall.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2025 Intel Corporation */ +#ifndef _X86_VIRT_SEAMCALL_H +#define _X86_VIRT_SEAMCALL_H + +#include +#include +#include +#include +#include + +u64 __seamcall(u64 fn, struct tdx_module_args *args); +u64 __seamcall_ret(u64 fn, struct tdx_module_args *args); +u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args); + +typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args); + +static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn, + struct tdx_module_args *args) +{ + lockdep_assert_preemption_disabled(); + + /* + * SEAMCALLs are made to the TDX module and can generate dirty + * cachelines of TDX private memory. Mark cache state incoherent + * so that the cache can be flushed during kexec. + * + * This needs to be done before actually making the SEAMCALL, + * because kexec-ing CPU could send NMI to stop remote CPUs, + * in which case even disabling IRQ won't help here. + */ + this_cpu_write(cache_state_incoherent, true); + + return func(fn, args); +} + +static __always_inline u64 sc_retry(sc_func_t func, u64 fn, + struct tdx_module_args *args) +{ + int retry =3D RDRAND_RETRY_LOOPS; + u64 ret; + + do { + ret =3D func(fn, args); + } while (ret =3D=3D TDX_RND_NO_ENTROPY && --retry); + + return ret; +} + +#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args)) +#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args)) +#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn= ), (_args)) + +typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *arg= s); + +static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *a= rgs) +{ + pr_err("SEAMCALL (%llu) failed: %#016llx\n", fn, err); +} + +static inline void seamcall_err_ret(u64 fn, u64 err, + struct tdx_module_args *args) +{ + seamcall_err(fn, err, args); + pr_err("RCX %#016llx RDX %#016llx R08 %#016llx\n", + args->rcx, args->rdx, args->r8); + pr_err("R09 %#016llx R10 %#016llx R11 %#016llx\n", + args->r9, args->r10, args->r11); +} + +static __always_inline int sc_retry_prerr(sc_func_t func, + sc_err_func_t err_func, + u64 fn, struct tdx_module_args *args) +{ + u64 sret =3D sc_retry(func, fn, args); + + if (sret =3D=3D TDX_SUCCESS) + return 0; + + if (sret =3D=3D TDX_SEAMCALL_VMFAILINVALID) + return -ENODEV; + + if (sret =3D=3D TDX_SEAMCALL_GP) + return -EOPNOTSUPP; + + if (sret =3D=3D TDX_SEAMCALL_UD) + return -EACCES; + + err_func(fn, sret, args); + return -EIO; +} + +#define seamcall_prerr(__fn, __args) \ + sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args)) + +#define seamcall_prerr_ret(__fn, __args) \ + sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args)) + +#endif diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 2218bb42af40..b44723ef4a14 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -39,6 +39,7 @@ #include #include #include +#include "seamcall.h" #include "tdx.h" =20 static u32 tdx_global_keyid __ro_after_init; @@ -59,51 +60,6 @@ static LIST_HEAD(tdx_memlist); =20 static struct tdx_sys_info tdx_sysinfo; =20 -typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *arg= s); - -static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *a= rgs) -{ - pr_err("SEAMCALL (%llu) failed: %#016llx\n", fn, err); -} - -static inline void seamcall_err_ret(u64 fn, u64 err, - struct tdx_module_args *args) -{ - seamcall_err(fn, err, args); - pr_err("RCX %#016llx RDX %#016llx R08 %#016llx\n", - args->rcx, args->rdx, args->r8); - pr_err("R09 %#016llx R10 %#016llx R11 %#016llx\n", - args->r9, args->r10, args->r11); -} - -static __always_inline int sc_retry_prerr(sc_func_t func, - sc_err_func_t err_func, - u64 fn, struct tdx_module_args *args) -{ - u64 sret =3D sc_retry(func, fn, args); - - if (sret =3D=3D TDX_SUCCESS) - return 0; - - if (sret =3D=3D TDX_SEAMCALL_VMFAILINVALID) - return -ENODEV; - - if (sret =3D=3D TDX_SEAMCALL_GP) - return -EOPNOTSUPP; - - if (sret =3D=3D TDX_SEAMCALL_UD) - return -EACCES; - - err_func(fn, sret, args); - return -EIO; -} - -#define seamcall_prerr(__fn, __args) \ - sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args)) - -#define seamcall_prerr_ret(__fn, __args) \ - sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args)) - /* * Do the module global initialization once and return its result. * It can be done on any cpu. It's always called with interrupts --=20 2.47.3