From: Kai Huang <kai.huang@intel.com>
To: x86@kernel.org
Cc: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
dave.hansen@intel.com, luto@kernel.org, kvm@vger.kernel.org,
pbonzini@redhat.com, seanjc@google.com, hpa@zytor.com,
peterz@infradead.org, kirill.shutemov@linux.intel.com,
sathyanarayanan.kuppuswamy@linux.intel.com, tony.luck@intel.com,
ak@linux.intel.com, dan.j.williams@intel.com,
chang.seok.bae@intel.com, keescook@chromium.org,
hengqi.arch@bytedance.com, laijs@linux.alibaba.com,
metze@samba.org, linux-kernel@vger.kernel.org,
kai.huang@intel.com
Subject: [RFC PATCH 17/21] x86/virt/tdx: Configure global KeyID on all packages
Date: Mon, 28 Feb 2022 15:13:05 +1300 [thread overview]
Message-ID: <21b8abec9044667a8137a2b1569c547dbf40641c.1646007267.git.kai.huang@intel.com> (raw)
In-Reply-To: <cover.1646007267.git.kai.huang@intel.com>
Before TDX module can use the global KeyID to access TDX metadata, the
key of the global KeyID must be configured on all physical packages via
TDH.SYS.KEY.CONFIG. This SEAMCALL cannot run concurrently on different
cpus since it exclusively acquires the TDX module.
Implement a helper to run SEAMCALL on one (any) cpu for all packages in
serialized way, and run TDH.SYS.KEY.CONFIG on all packages using the
helper.
The TDX module uses the global KeyID to initialize its metadata (PAMTs).
Before TDX module can do that, all cachelines of PAMTs must be flushed.
Otherwise, they may silently corrupt the PAMTs later initialized by the
TDX module.
Use wbinvd to flush cache as PAMTs can be potentially large (~1/256th of
system RAM).
Flush cache before configuring the global KeyID on all packages, as
suggested by TDX specification. In practice, the current generation of
TDX doesn't use the global KeyID in TDH.SYS.KEY.CONFIG. Therefore in
practice flushing cache can be done after configuring the global KeyID
is done on all packages. But the future generation of TDX may change
this behaviour, so just follow TDX specification's suggestion to flush
cache before configuring the global KeyID on all packages.
Signed-off-by: Kai Huang <kai.huang@intel.com>
---
arch/x86/virt/vmx/tdx.c | 94 ++++++++++++++++++++++++++++++++++++++++-
arch/x86/virt/vmx/tdx.h | 1 +
2 files changed, 94 insertions(+), 1 deletion(-)
diff --git a/arch/x86/virt/vmx/tdx.c b/arch/x86/virt/vmx/tdx.c
index 008628674a2f..22cbc43873c9 100644
--- a/arch/x86/virt/vmx/tdx.c
+++ b/arch/x86/virt/vmx/tdx.c
@@ -22,6 +22,7 @@
#include <asm/virtext.h>
#include <asm/e820/api.h>
#include <asm/pgtable.h>
+#include <asm/smp.h>
#include <asm/tdx.h>
#include "tdx.h"
@@ -397,6 +398,47 @@ static int seamcall_on_each_cpu(struct seamcall_ctx *sc)
return atomic_read(&sc->err);
}
+/*
+ * Call the SEAMCALL on one (any) cpu for each physical package in
+ * serialized way. Note for serialized calls 'seamcall_ctx::err'
+ * doesn't have to be atomic, but for simplicity just reuse it
+ * instead of adding a new one.
+ *
+ * Return -ENXIO if IPI SEAMCALL wasn't run on any cpu, or -EFAULT
+ * when SEAMCALL fails, or -EPERM when the cpu where SEAMCALL runs
+ * on is not in VMX operation. In case of -EFAULT, the error code
+ * of SEAMCALL is in 'struct seamcall_ctx::seamcall_ret'.
+ */
+static int seamcall_on_each_package_serialized(struct seamcall_ctx *sc)
+{
+ cpumask_var_t packages;
+ int cpu, ret;
+
+ if (!zalloc_cpumask_var(&packages, GFP_KERNEL))
+ return -ENOMEM;
+
+ for_each_online_cpu(cpu) {
+ if (cpumask_test_and_set_cpu(topology_physical_package_id(cpu),
+ packages))
+ continue;
+
+ ret = smp_call_function_single(cpu, seamcall_smp_call_function,
+ sc, true);
+ if (ret)
+ return ret;
+
+ /*
+ * Doesn't have to use atomic_read(), but it doesn't
+ * hurt either.
+ */
+ ret = atomic_read(&sc->err);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static inline bool p_seamldr_ready(void)
{
return !!p_seamldr_info.p_seamldr_ready;
@@ -1239,6 +1281,18 @@ static int config_tdx_module(struct tdmr_info **tdmr_array, int tdmr_num,
return ret;
}
+static int config_global_keyid(u64 global_keyid)
+{
+ struct seamcall_ctx sc = { .fn = TDH_SYS_KEY_CONFIG };
+
+ /*
+ * TDH.SYS.KEY.CONFIG may fail with entropy error (which is
+ * a recoverable error). Assume this is exceedingly rare and
+ * just return error if encountered instead of retrying.
+ */
+ return seamcall_on_each_package_serialized(&sc);
+}
+
static int init_tdx_module(void)
{
struct tdmr_info **tdmr_array;
@@ -1289,6 +1343,37 @@ static int init_tdx_module(void)
if (ret)
goto out_free_pamts;
+ /*
+ * The same physical address associated with different KeyIDs
+ * has separate cachelines. Before using the new KeyID to access
+ * some memory, the cachelines associated with the old KeyID must
+ * be flushed, otherwise they may later silently corrupt the data
+ * written with the new KeyID. After cachelines associated with
+ * the old KeyID are flushed, CPU speculative fetch using the old
+ * KeyID is OK since the prefetched cachelines won't be consumed
+ * by CPU core.
+ *
+ * TDX module initializes PAMTs using the global KeyID to crypto
+ * protect them from malicious host. Before that, the PAMTs are
+ * used by kernel (with KeyID 0) and the cachelines associated
+ * with the PAMTs must be flushed. Given PAMTs are potentially
+ * large (~1/256th of system RAM), just use WBINVD on all cpus to
+ * flush the cache.
+ *
+ * In practice, the current generation of TDX doesn't use the
+ * global KeyID in TDH.SYS.KEY.CONFIG. Therefore in practice,
+ * the cachelines can be flushed after configuring the global
+ * KeyID on all pkgs is done. But the future generation of TDX
+ * may change this, so just follow the suggestion of TDX spec to
+ * flush cache before TDH.SYS.KEY.CONFIG.
+ */
+ wbinvd_on_all_cpus();
+
+ /* Config the key of global KeyID on all packages */
+ ret = config_global_keyid(tdx_global_keyid);
+ if (ret)
+ goto out_free_pamts;
+
/*
* Return -EFAULT until all steps of TDX module
* initialization are done.
@@ -1299,8 +1384,15 @@ static int init_tdx_module(void)
* Free PAMTs allocated in construct_tdmrs() when TDX module
* initialization fails.
*/
- if (ret)
+ if (ret) {
+ /*
+ * Part of PAMTs may already have been initialized by
+ * TDX module. Flush cache before returning them back
+ * to kernel.
+ */
+ wbinvd_on_all_cpus();
tdmrs_free_pamt_all(tdmr_array, tdmr_num);
+ }
out_free_tdmrs:
/*
* TDMRs are only used during initializing TDX module. Always
diff --git a/arch/x86/virt/vmx/tdx.h b/arch/x86/virt/vmx/tdx.h
index d8e2800397af..bba8cabea4bb 100644
--- a/arch/x86/virt/vmx/tdx.h
+++ b/arch/x86/virt/vmx/tdx.h
@@ -122,6 +122,7 @@ struct tdmr_info {
/*
* TDX module SEAMCALL leaf functions
*/
+#define TDH_SYS_KEY_CONFIG 31
#define TDH_SYS_INFO 32
#define TDH_SYS_INIT 33
#define TDH_SYS_LP_INIT 35
--
2.33.1
next prev parent reply other threads:[~2022-02-28 2:15 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-28 2:12 [RFC PATCH 00/21] TDX host kernel support Kai Huang
2022-02-28 2:12 ` [RFC PATCH 01/21] x86/virt/tdx: Detect SEAM Kai Huang
2022-02-28 2:12 ` [RFC PATCH 02/21] x86/virt/tdx: Detect TDX private KeyIDs Kai Huang
2022-02-28 2:12 ` [RFC PATCH 03/21] x86/virt/tdx: Implement the SEAMCALL base function Kai Huang
2022-02-28 2:12 ` [RFC PATCH 04/21] x86/virt/tdx: Add skeleton for detecting and initializing TDX on demand Kai Huang
2022-02-28 2:12 ` [RFC PATCH 05/21] x86/virt/tdx: Detect P-SEAMLDR and TDX module Kai Huang
2022-02-28 2:12 ` [RFC PATCH 06/21] x86/virt/tdx: Shut down TDX module in case of error Kai Huang
2022-02-28 2:12 ` [RFC PATCH 07/21] x86/virt/tdx: Do TDX module global initialization Kai Huang
2022-02-28 2:12 ` [RFC PATCH 08/21] x86/virt/tdx: Do logical-cpu scope TDX module initialization Kai Huang
2022-02-28 2:12 ` [RFC PATCH 09/21] x86/virt/tdx: Get information about TDX module and convertible memory Kai Huang
2022-02-28 2:12 ` [RFC PATCH 10/21] x86/virt/tdx: Add placeholder to coveret all system RAM as TDX memory Kai Huang
2022-02-28 2:12 ` [RFC PATCH 11/21] x86/virt/tdx: Choose to use " Kai Huang
2022-02-28 2:13 ` [RFC PATCH 12/21] x86/virt/tdx: Create TDMRs to cover all system RAM Kai Huang
2022-02-28 2:13 ` [RFC PATCH 13/21] x86/virt/tdx: Allocate and set up PAMTs for TDMRs Kai Huang
2022-02-28 2:13 ` [RFC PATCH 14/21] x86/virt/tdx: Set up reserved areas for all TDMRs Kai Huang
2022-02-28 2:13 ` [RFC PATCH 15/21] x86/virt/tdx: Reserve TDX module global KeyID Kai Huang
2022-02-28 2:13 ` [RFC PATCH 16/21] x86/virt/tdx: Configure TDX module with TDMRs and " Kai Huang
2022-02-28 2:13 ` Kai Huang [this message]
2022-02-28 2:13 ` [RFC PATCH 18/21] x86/virt/tdx: Initialize all TDMRs Kai Huang
2022-02-28 2:13 ` [RFC PATCH 19/21] x86: Flush cache of TDX private memory during kexec() Kai Huang
2022-02-28 2:13 ` [RFC PATCH 20/21] x86/virt/tdx: Add kernel command line to opt-in TDX host support Kai Huang
2022-02-28 2:13 ` [RFC PATCH 21/21] Documentation/x86: Add documentation for " Kai Huang
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=21b8abec9044667a8137a2b1569c547dbf40641c.1646007267.git.kai.huang@intel.com \
--to=kai.huang@intel.com \
--cc=ak@linux.intel.com \
--cc=bp@alien8.de \
--cc=chang.seok.bae@intel.com \
--cc=dan.j.williams@intel.com \
--cc=dave.hansen@intel.com \
--cc=hengqi.arch@bytedance.com \
--cc=hpa@zytor.com \
--cc=keescook@chromium.org \
--cc=kirill.shutemov@linux.intel.com \
--cc=kvm@vger.kernel.org \
--cc=laijs@linux.alibaba.com \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=metze@samba.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=sathyanarayanan.kuppuswamy@linux.intel.com \
--cc=seanjc@google.com \
--cc=tglx@linutronix.de \
--cc=tony.luck@intel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®