From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.15]) (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 4BA2F3E866D; Tue, 31 Mar 2026 12:43:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.15 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774961015; cv=none; b=mu6fYfnCbi5Jphk26pXP2xHc+oUU2HZn6w9GH3lWTPteHuDT7pryRw2wsgFshACwWF3Oe+ija5k/Ang5MY3FD8W29LQ2TqNq90LSkiNHGAwoRtVMqQzqUC5LELdHjs1ZRLW2xslM8bWfv6FT3q8Msr6Lf4ACvdY6VjMbV0AF2Sc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774961015; c=relaxed/simple; bh=4G4RQtu1tm+xJgr1GnnHG6jkIJWZoO+nxf83tGmQO/I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=M2z/IZ1w7K/W8BROCEOQWT0qRSnYEU/mgKu4Jm+NgoXWBcYymV66U/OjwIDEpYyHTTGKYBjNYQZid4WcfQ5E5sNaNmqCCNZKomQr2IO81/OCNUZR5QXgg4dntR2JgjlmipHbJowxASartwsXNeEuMAoD7DrGyLX6yhoFmTGQ/bI= 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=dsHPYhRe; arc=none smtp.client-ip=192.198.163.15 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="dsHPYhRe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1774961013; x=1806497013; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4G4RQtu1tm+xJgr1GnnHG6jkIJWZoO+nxf83tGmQO/I=; b=dsHPYhReXXQq+YqOM+vSqMjZwJatGl/WrmX2JYFu03z6BWKwNyFe/Oy6 U8re6047fLw2yKkKPEMXGv+GkJsHDcOsspNuKE302WaILWwAybswbOoge WkMeNU0vVwcqrklTqZcJkRi/RoJO/zsD7MvIvquuF17LRJW0UEOt8BH06 30d0bNsDT5tHhw8fW4bYl7+7fOVrLMIGPEkaR7sEm+U15KwAohu0M/EEc KPRQjOJAl3VGEQRn3Pnig1ca+Q3kg3vBunDtoZi8h8M76y8SkRo17eEoV tM3LZYaaqulebAnofZkehxFtWIMQUiqwPdc9u4i87j5ShwgA/vWrtutDI A==; X-CSE-ConnectionGUID: kFEHDaOmTSeqqwgFshllbg== X-CSE-MsgGUID: /Y6VuLoaTbSPtpIYiu28sw== X-IronPort-AV: E=McAfee;i="6800,10657,11745"; a="76084518" X-IronPort-AV: E=Sophos;i="6.23,151,1770624000"; d="scan'208";a="76084518" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by fmvoesa109.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Mar 2026 05:43:32 -0700 X-CSE-ConnectionGUID: mRfLcan6QYKBL1oDBk9loQ== X-CSE-MsgGUID: 0aLDGSjXSM+WL47p09gKKg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,151,1770624000"; d="scan'208";a="221492124" Received: from 984fee019967.jf.intel.com ([10.23.153.244]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Mar 2026 05:43:31 -0700 From: Chao Gao To: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, kvm@vger.kernel.org Cc: binbin.wu@linux.intel.com, dan.j.williams@intel.com, dave.hansen@linux.intel.com, ira.weiny@intel.com, kai.huang@intel.com, kas@kernel.org, nik.borisov@suse.com, paulmck@kernel.org, pbonzini@redhat.com, reinette.chatre@intel.com, rick.p.edgecombe@intel.com, sagis@google.com, seanjc@google.com, tony.lindgren@linux.intel.com, vannapurve@google.com, vishal.l.verma@intel.com, yilun.xu@linux.intel.com, xiaoyao.li@intel.com, yan.y.zhao@intel.com, Chao Gao , Thomas Gleixner , Ingo Molnar , Borislav Petkov , x86@kernel.org, "H. Peter Anvin" Subject: [PATCH v7 11/22] x86/virt/seamldr: Shut down the current TDX module Date: Tue, 31 Mar 2026 05:41:24 -0700 Message-ID: <20260331124214.117808-12-chao.gao@intel.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260331124214.117808-1-chao.gao@intel.com> References: <20260331124214.117808-1-chao.gao@intel.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first step of TDX module updates is shutting down the current TDX Module. This step also packs state information that needs to be preserved across updates as handoff data, which will be consumed by the updated module. The handoff data is stored internally in the SEAM range and is hidden from the kernel. To ensure a successful update, the new module must be able to consume the handoff data generated by the old module. Since handoff data layout may change between modules, the handoff data is versioned. Each module has a native handoff version and provides backward support for several older versions. The complete handoff versioning protocol is complex as it supports both module upgrades and downgrades. See details in IntelĀ® Trust Domain Extensions (IntelĀ® TDX) Module Base Architecture Specification, Chapter "Handoff Versioning". Ideally, the kernel needs to retrieve the handoff versions supported by the current module and the new module and select a version supported by both. But, since this implementation chooses to only support module upgrades, simply request the current module to generate handoff data using its highest supported version, expecting that the new module will likely support it. Note that only one CPU needs to call the TDX module's shutdown API. Signed-off-by: Chao Gao Reviewed-by: Tony Lindgren Reviewed-by: Xu Yilun Reviewed-by: Kai Huang Reviewed-by: Kiryl Shutsemau (Meta) --- v5: - Massage changelog [Kai] - Avoid "refers to the global copy while populating the tdx_sys_info passed as a pointer" [Rick/Yilun] v4: - skip the whole handoff metadata if runtime updates are not supported [Yilun] v3: - remove autogeneration stuff in the changelog v2: - add a comment about how handoff version is chosen. - remove the first !ret in get_tdx_sys_info_handoff() as we edited the auto-generated code anyway - remove !! when determining whether a CPU is the primary one - remove unnecessary if-break nesting in TDP_SHUTDOWN --- arch/x86/include/asm/tdx_global_metadata.h | 5 +++++ arch/x86/virt/vmx/tdx/seamldr.c | 11 ++++++++++- arch/x86/virt/vmx/tdx/tdx.c | 15 +++++++++++++++ arch/x86/virt/vmx/tdx/tdx.h | 3 +++ arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 20 ++++++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/asm/tdx_global_metadata.h index 40689c8dc67e..8a9ebd895e70 100644 --- a/arch/x86/include/asm/tdx_global_metadata.h +++ b/arch/x86/include/asm/tdx_global_metadata.h @@ -40,12 +40,17 @@ struct tdx_sys_info_td_conf { u64 cpuid_config_values[128][2]; }; +struct tdx_sys_info_handoff { + u16 module_hv; +}; + struct tdx_sys_info { struct tdx_sys_info_version version; struct tdx_sys_info_features features; struct tdx_sys_info_tdmr tdmr; struct tdx_sys_info_td_ctrl td_ctrl; struct tdx_sys_info_td_conf td_conf; + struct tdx_sys_info_handoff handoff; }; #endif diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c index 5964bbc67944..a8bfa30ee55f 100644 --- a/arch/x86/virt/vmx/tdx/seamldr.c +++ b/arch/x86/virt/vmx/tdx/seamldr.c @@ -15,6 +15,7 @@ #include #include "seamcall_internal.h" +#include "tdx.h" /* P-SEAMLDR SEAMCALL leaf function */ #define P_SEAMLDR_INFO 0x8000000000000000 @@ -207,6 +208,7 @@ static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size) */ enum module_update_state { MODULE_UPDATE_START, + MODULE_UPDATE_SHUTDOWN, MODULE_UPDATE_DONE, }; @@ -246,8 +248,12 @@ static void ack_state(void) static int do_seamldr_install_module(void *seamldr_params) { enum module_update_state newstate, curstate = MODULE_UPDATE_START; + int cpu = smp_processor_id(); + bool primary; int ret = 0; + primary = cpumask_first(cpu_online_mask) == cpu; + do { /* Chill out and re-read update_data. */ cpu_relax(); @@ -256,7 +262,10 @@ static int do_seamldr_install_module(void *seamldr_params) if (newstate != curstate) { curstate = newstate; switch (curstate) { - /* TODO: add the update steps. */ + case MODULE_UPDATE_SHUTDOWN: + if (primary) + ret = tdx_module_shutdown(); + break; default: break; } diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 172f6d4133b5..f87fad429f4e 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1176,6 +1176,21 @@ int tdx_enable(void) } EXPORT_SYMBOL_FOR_KVM(tdx_enable); +int tdx_module_shutdown(void) +{ + struct tdx_module_args args = {}; + + /* + * Shut down the TDX module and prepare handoff data for the next + * TDX module. This SEAMCALL requires a handoff version. Use the + * module's handoff version, as it is the highest version the + * module can produce and is more likely to be supported by new + * modules as new modules likely have higher handoff version. + */ + args.rcx = tdx_sysinfo.handoff.module_hv; + return seamcall_prerr(TDH_SYS_SHUTDOWN, &args); +} + static bool is_pamt_page(unsigned long phys) { struct tdmr_info_list *tdmr_list = &tdx_tdmr_list; diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 82bb82be8567..1c4da9540ae0 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -46,6 +46,7 @@ #define TDH_PHYMEM_PAGE_WBINVD 41 #define TDH_VP_WR 43 #define TDH_SYS_CONFIG 45 +#define TDH_SYS_SHUTDOWN 52 /* * SEAMCALL leaf: @@ -118,4 +119,6 @@ struct tdmr_info_list { int max_tdmrs; /* How many 'tdmr_info's are allocated */ }; +int tdx_module_shutdown(void); + #endif diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c index 34c050d74b56..225e157805e8 100644 --- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c +++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c @@ -100,6 +100,19 @@ static int get_tdx_sys_info_td_conf(struct tdx_sys_info_td_conf *sysinfo_td_conf return ret; } +static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff) +{ + int ret; + u64 val; + + ret = read_sys_metadata_field(0x8900000100000000, &val); + if (ret) + return ret; + + sysinfo_handoff->module_hv = val; + return 0; +} + static int get_tdx_sys_info(struct tdx_sys_info *sysinfo) { int ret = 0; @@ -116,5 +129,12 @@ static int get_tdx_sys_info(struct tdx_sys_info *sysinfo) ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl); ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf); + /* + * Don't treat a module that doesn't support update as a failure. + * Only read the metadata optionally. + */ + if (tdx_supports_runtime_update(sysinfo)) + ret = ret ?: get_tdx_sys_info_handoff(&sysinfo->handoff); + return ret; } -- 2.47.3