Message ID | 2337c8e9086a006aaa2c4b99caf478420d1fc640.1668988357.git.kai.huang@intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp1327420wrr; Sun, 20 Nov 2022 16:48:04 -0800 (PST) X-Google-Smtp-Source: AA0mqf6hA6MdwuNmcXl1EZdbz79m024NnM+eGRaNFV1txu0T0SIXWHzzxQW894+yuQNn7VvCUP1w X-Received: by 2002:a17:902:dac2:b0:188:f5c7:4d23 with SMTP id q2-20020a170902dac200b00188f5c74d23mr9586414plx.125.1668991684487; Sun, 20 Nov 2022 16:48:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668991684; cv=none; d=google.com; s=arc-20160816; b=q+YemIQFhOt9bqOeM8rXqc2KCDvk0f/BPVvXNA8lfrQuoZ5gPM8yEi38dL9zgqG+yU c0rOjSVSkvOE4bdM1AVEYT2UszChrfWEYiOxmNX4RuQcVR1t37N6sTVNWJsxegVLYxo1 9BpwohgsYToh8fSeKJdnnwcCsB3SRu4LvUkuJBN7E5ERSGNhb1RC8sONwAJmVMKjni7m U3Gi7XRKtJnxBbDhQCIh1GwSoy+tlcvqIrgtg+S9BSlBoZef/j5DKjzmCXdpPJeI5vdO tnw6GcTd4mGfjcPs4C1BaBZxMHeeHNlFa2Wse02KHsUDJAm4oO2FJcAOcXoIqqdICb+X yQrA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=RZ2vana1oXRQxzEh9aeGfPQU1eY3ER67EJl735YSoOo=; b=r6Lr1WXj6Hj0V//25CFTQUkYmHkDrYrA4EDmxH4uiylPm4X/A8oWQxJxRwHGhgEsnE radrDP40g6etN9otimWVkYreIrTFYiRbtTvl4gSBP/z+lJgmwSSMjrxZKosjGz7upT/9 XrtpYEezhQJ5ZqeHu4C6ruOh2KgFSx/KqSGzNXdxsh9b1254YlAgIjFnjAw0sXTbN9rS xyhAk4+fIeLKi6S0eInKpVSbeQYrhc86XwIXRqC4XmDegwvQ26EJm3zxTJWQgZC2GJkU RCllFoJUTYdWnQk2qd4UpnzFWveBnM2U2Au7ucBSbOIdrFLfd0P/7fX9LVaXt2pEb5IN nLUQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=MEWNWzv7; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id c11-20020a170902d48b00b001769fce8c2fsi10814545plg.485.2022.11.20.16.47.51; Sun, 20 Nov 2022 16:48:04 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=MEWNWzv7; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230124AbiKUAbM (ORCPT <rfc822;leviz.kernel.dev@gmail.com> + 99 others); Sun, 20 Nov 2022 19:31:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58622 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229934AbiKUAa2 (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Sun, 20 Nov 2022 19:30:28 -0500 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F3F035E9F5; Sun, 20 Nov 2022 16:28:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668990537; x=1700526537; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3LwZ/2jAQ0M9UrYz1pvBJwdZZg6HBZnO8RRBVvS9No4=; b=MEWNWzv7JAUBF48uSWNG2sSZ3wzkfCIr540XtHyg5JHJDcgYWp9O7RDR q9Jgh7t58bqjgrnVtkf9e1wOyU7CetgPLG3bso9IjTH/IeVBgksl8dzmp Cfb72x7Uu1ZNlmR2gsG48uFzMhfg4sRyYbbrrLP2RL4NfGbD7IO2v+2de zw2j9eD0kB4hi0MmD1o4LlF1L1iX2k5/UFLYUo6yVPMnW62uzdpOPanhq u4xy1gYyVEPhb/wgPxHXVI5UGQmDQYdfL68E7z7MOn4ZLax52oTjf1d0V K7vWjSTaguOAgf/OmifHTjidF0Za9wU9r1eKCB7VOAYwfnObwLHxmjrys Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10537"; a="377705762" X-IronPort-AV: E=Sophos;i="5.96,180,1665471600"; d="scan'208";a="377705762" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Nov 2022 16:28:13 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10537"; a="729825550" X-IronPort-AV: E=Sophos;i="5.96,180,1665471600"; d="scan'208";a="729825550" Received: from tomnavar-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.176.15]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Nov 2022 16:28:09 -0800 From: Kai Huang <kai.huang@intel.com> To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, seanjc@google.com, pbonzini@redhat.com, dave.hansen@intel.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, peterz@infradead.org, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v7 18/20] x86/virt/tdx: Initialize all TDMRs Date: Mon, 21 Nov 2022 13:26:40 +1300 Message-Id: <2337c8e9086a006aaa2c4b99caf478420d1fc640.1668988357.git.kai.huang@intel.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <cover.1668988357.git.kai.huang@intel.com> References: <cover.1668988357.git.kai.huang@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1750064624533406583?= X-GMAIL-MSGID: =?utf-8?q?1750064624533406583?= |
Series |
TDX host kernel support
|
|
Commit Message
Kai Huang
Nov. 21, 2022, 12:26 a.m. UTC
Initialize TDMRs via TDH.SYS.TDMR.INIT as the last step to complete the TDX initialization. All TDMRs need to be initialized using TDH.SYS.TDMR.INIT SEAMCALL before the memory pages can be used by the TDX module. The time to initialize TDMR is proportional to the size of the TDMR because TDH.SYS.TDMR.INIT internally initializes the PAMT entries using the global KeyID. To avoid long latency caused in one SEAMCALL, TDH.SYS.TDMR.INIT only initializes an (implementation-specific) subset of PAMT entries of one TDMR in one invocation. The caller needs to call TDH.SYS.TDMR.INIT iteratively until all PAMT entries of the given TDMR are initialized. TDH.SYS.TDMR.INITs can run concurrently on multiple CPUs as long as they are initializing different TDMRs. To keep it simple, just initialize all TDMRs one by one. On a 2-socket machine with 2.2G CPUs and 64GB memory, each TDH.SYS.TDMR.INIT roughly takes couple of microseconds on average, and it takes roughly dozens of milliseconds to complete the initialization of all TDMRs while system is idle. Reviewed-by: Isaku Yamahata <isaku.yamahata@intel.com> Signed-off-by: Kai Huang <kai.huang@intel.com> --- v6 -> v7: - Removed need_resched() check. -- Andi. --- arch/x86/virt/vmx/tdx/tdx.c | 69 ++++++++++++++++++++++++++++++++++--- arch/x86/virt/vmx/tdx/tdx.h | 1 + 2 files changed, 65 insertions(+), 5 deletions(-)
Comments
On 11/20/22 16:26, Kai Huang wrote: > Initialize TDMRs via TDH.SYS.TDMR.INIT as the last step to complete the > TDX initialization. > > All TDMRs need to be initialized using TDH.SYS.TDMR.INIT SEAMCALL before > the memory pages can be used by the TDX module. The time to initialize > TDMR is proportional to the size of the TDMR because TDH.SYS.TDMR.INIT > internally initializes the PAMT entries using the global KeyID. > > To avoid long latency caused in one SEAMCALL, TDH.SYS.TDMR.INIT only > initializes an (implementation-specific) subset of PAMT entries of one > TDMR in one invocation. The caller needs to call TDH.SYS.TDMR.INIT > iteratively until all PAMT entries of the given TDMR are initialized. > > TDH.SYS.TDMR.INITs can run concurrently on multiple CPUs as long as they > are initializing different TDMRs. To keep it simple, just initialize > all TDMRs one by one. On a 2-socket machine with 2.2G CPUs and 64GB > memory, each TDH.SYS.TDMR.INIT roughly takes couple of microseconds on > average, and it takes roughly dozens of milliseconds to complete the > initialization of all TDMRs while system is idle. Any chance you could say TDH.SYS.TDMR.INIT a few more times in there? ;) Seriously, please try to trim that down. If you talk about the implementation in detail in the code comments, don't cover it in detail in the changelog too. Also, this is a momentous patch, right? It's the last piece. Maybe worth calling that out. > diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c > index 99d1be5941a7..9bcdb30b7a80 100644 > --- a/arch/x86/virt/vmx/tdx/tdx.c > +++ b/arch/x86/virt/vmx/tdx/tdx.c > @@ -1066,6 +1066,65 @@ static int config_global_keyid(void) > return seamcall_on_each_package_serialized(&sc); > } > > +/* Initialize one TDMR */ Does this comment add value? Even if it does, it is better than naming the dang function init_one_tdmr()? > +static int init_tdmr(struct tdmr_info *tdmr) > +{ > + u64 next; > + > + /* > + * Initializing PAMT entries might be time-consuming (in > + * proportion to the size of the requested TDMR). To avoid long > + * latency in one SEAMCALL, TDH.SYS.TDMR.INIT only initializes > + * an (implementation-defined) subset of PAMT entries in one > + * invocation. > + * > + * Call TDH.SYS.TDMR.INIT iteratively until all PAMT entries > + * of the requested TDMR are initialized (if next-to-initialize > + * address matches the end address of the TDMR). > + */ The PAMT discussion here is, IMNHO silly. If this were about initializing PAMT's then it should be renamed init_pamts() and the SEAMCALL should be called PAMT_INIT or soemthing. It's not, and the ABI is built around the TDMR and *its* addresses. Let's chop this comment down: /* * Initializing a TDMR can be time consuming. To avoid long * SEAMCALLs, the TDX module may only initialize a part of the * TDMR in each call. */ Talk about the looping logic in the loop. > + do { > + struct tdx_module_output out; > + int ret; > + > + ret = seamcall(TDH_SYS_TDMR_INIT, tdmr->base, 0, 0, 0, NULL, > + &out); > + if (ret) > + return ret; > + /* > + * RDX contains 'next-to-initialize' address if > + * TDH.SYS.TDMR.INT succeeded. > + */ > + next = out.rdx; > + /* Allow scheduling when needed */ That comment is a wee bit superfluous, don't you think? > + cond_resched(); /* Keep making SEAMCALLs until the TDMR is done */ > + } while (next < tdmr->base + tdmr->size); > + > + return 0; > +} > + > +/* Initialize all TDMRs */ Does this comment add value? > +static int init_tdmrs(struct tdmr_info *tdmr_array, int tdmr_num) > +{ > + int i; > + > + /* > + * Initialize TDMRs one-by-one for simplicity, though the TDX > + * architecture does allow different TDMRs to be initialized in > + * parallel on multiple CPUs. Parallel initialization could > + * be added later when the time spent in the serialized scheme > + * becomes a real concern. > + */ Trim down the comment: /* * This operation is costly. It can be parallelized, * but keep it simple for now. */ > + for (i = 0; i < tdmr_num; i++) { > + int ret; > + > + ret = init_tdmr(tdmr_array_entry(tdmr_array, i)); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > /* > * Detect and initialize the TDX module. > * > @@ -1172,11 +1231,11 @@ static int init_tdx_module(void) > if (ret) > goto out_free_pamts; > > - /* > - * Return -EINVAL until all steps of TDX module initialization > - * process are done. > - */ > - ret = -EINVAL; > + /* Initialize TDMRs to complete the TDX module initialization */ > + ret = init_tdmrs(tdmr_array, tdmr_num); > + if (ret) > + goto out_free_pamts; > + > out_free_pamts: > if (ret) { > /* > diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h > index 768d097412ab..891691b1ea50 100644 > --- a/arch/x86/virt/vmx/tdx/tdx.h > +++ b/arch/x86/virt/vmx/tdx/tdx.h > @@ -19,6 +19,7 @@ > #define TDH_SYS_INFO 32 > #define TDH_SYS_INIT 33 > #define TDH_SYS_LP_INIT 35 > +#define TDH_SYS_TDMR_INIT 36 > #define TDH_SYS_LP_SHUTDOWN 44 > #define TDH_SYS_CONFIG 45 >
On Wed, 2022-11-23 at 16:42 -0800, Dave Hansen wrote: > On 11/20/22 16:26, Kai Huang wrote: > > Initialize TDMRs via TDH.SYS.TDMR.INIT as the last step to complete the > > TDX initialization. > > > > All TDMRs need to be initialized using TDH.SYS.TDMR.INIT SEAMCALL before > > the memory pages can be used by the TDX module. The time to initialize > > TDMR is proportional to the size of the TDMR because TDH.SYS.TDMR.INIT > > internally initializes the PAMT entries using the global KeyID. > > > > To avoid long latency caused in one SEAMCALL, TDH.SYS.TDMR.INIT only > > initializes an (implementation-specific) subset of PAMT entries of one > > TDMR in one invocation. The caller needs to call TDH.SYS.TDMR.INIT > > iteratively until all PAMT entries of the given TDMR are initialized. > > > > TDH.SYS.TDMR.INITs can run concurrently on multiple CPUs as long as they > > are initializing different TDMRs. To keep it simple, just initialize > > all TDMRs one by one. On a 2-socket machine with 2.2G CPUs and 64GB > > memory, each TDH.SYS.TDMR.INIT roughly takes couple of microseconds on > > average, and it takes roughly dozens of milliseconds to complete the > > initialization of all TDMRs while system is idle. > > Any chance you could say TDH.SYS.TDMR.INIT a few more times in there? ;) I am a bad changelog writer. > > Seriously, please try to trim that down. If you talk about the > implementation in detail in the code comments, don't cover it in detail > in the changelog too. Yes will use this tip to trim down. Thanks for the tip. > > Also, this is a momentous patch, right? It's the last piece. Maybe > worth calling that out. Yes this is the last step of initializing the TDX module. It is sort of mentioned in the first sentence of this changelong: Initialize TDMRs via TDH.SYS.TDMR.INIT as the last step to complete the TDX initialization. But perhaps it can be more explicitly. > > > diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c > > index 99d1be5941a7..9bcdb30b7a80 100644 > > --- a/arch/x86/virt/vmx/tdx/tdx.c > > +++ b/arch/x86/virt/vmx/tdx/tdx.c > > @@ -1066,6 +1066,65 @@ static int config_global_keyid(void) > > return seamcall_on_each_package_serialized(&sc); > > } > > > > +/* Initialize one TDMR */ > > Does this comment add value? Even if it does, it is better than naming > the dang function init_one_tdmr()? Sorry will try best to avoid such type of comments in the future. > > > +static int init_tdmr(struct tdmr_info *tdmr) > > +{ > > + u64 next; > > + > > + /* > > + * Initializing PAMT entries might be time-consuming (in > > + * proportion to the size of the requested TDMR). To avoid long > > + * latency in one SEAMCALL, TDH.SYS.TDMR.INIT only initializes > > + * an (implementation-defined) subset of PAMT entries in one > > + * invocation. > > + * > > + * Call TDH.SYS.TDMR.INIT iteratively until all PAMT entries > > + * of the requested TDMR are initialized (if next-to-initialize > > + * address matches the end address of the TDMR). > > + */ > > The PAMT discussion here is, IMNHO silly. If this were about > initializing PAMT's then it should be renamed init_pamts() and the > SEAMCALL should be called PAMT_INIT or soemthing. It's not, and the ABI > is built around the TDMR and *its* addresses. Agreed. > > Let's chop this comment down: > > /* > * Initializing a TDMR can be time consuming. To avoid long > * SEAMCALLs, the TDX module may only initialize a part of the > * TDMR in each call. > */ > > Talk about the looping logic in the loop. Agreed. Thanks. > > > + do { > > + struct tdx_module_output out; > > + int ret; > > + > > + ret = seamcall(TDH_SYS_TDMR_INIT, tdmr->base, 0, 0, 0, NULL, > > + &out); > > + if (ret) > > + return ret; > > + /* > > + * RDX contains 'next-to-initialize' address if > > + * TDH.SYS.TDMR.INT succeeded. > > + */ > > + next = out.rdx; > > + /* Allow scheduling when needed */ > > That comment is a wee bit superfluous, don't you think? Indeed. > > > + cond_resched(); > > /* Keep making SEAMCALLs until the TDMR is done */ > > > + } while (next < tdmr->base + tdmr->size); > > + > > + return 0; > > +} > > + > > +/* Initialize all TDMRs */ > > Does this comment add value? No. Will remove. > > > +static int init_tdmrs(struct tdmr_info *tdmr_array, int tdmr_num) > > +{ > > + int i; > > + > > + /* > > + * Initialize TDMRs one-by-one for simplicity, though the TDX > > + * architecture does allow different TDMRs to be initialized in > > + * parallel on multiple CPUs. Parallel initialization could > > + * be added later when the time spent in the serialized scheme > > + * becomes a real concern. > > + */ > > Trim down the comment: > > /* > * This operation is costly. It can be parallelized, > * but keep it simple for now. > */ Thanks. [...]
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 99d1be5941a7..9bcdb30b7a80 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1066,6 +1066,65 @@ static int config_global_keyid(void) return seamcall_on_each_package_serialized(&sc); } +/* Initialize one TDMR */ +static int init_tdmr(struct tdmr_info *tdmr) +{ + u64 next; + + /* + * Initializing PAMT entries might be time-consuming (in + * proportion to the size of the requested TDMR). To avoid long + * latency in one SEAMCALL, TDH.SYS.TDMR.INIT only initializes + * an (implementation-defined) subset of PAMT entries in one + * invocation. + * + * Call TDH.SYS.TDMR.INIT iteratively until all PAMT entries + * of the requested TDMR are initialized (if next-to-initialize + * address matches the end address of the TDMR). + */ + do { + struct tdx_module_output out; + int ret; + + ret = seamcall(TDH_SYS_TDMR_INIT, tdmr->base, 0, 0, 0, NULL, + &out); + if (ret) + return ret; + /* + * RDX contains 'next-to-initialize' address if + * TDH.SYS.TDMR.INT succeeded. + */ + next = out.rdx; + /* Allow scheduling when needed */ + cond_resched(); + } while (next < tdmr->base + tdmr->size); + + return 0; +} + +/* Initialize all TDMRs */ +static int init_tdmrs(struct tdmr_info *tdmr_array, int tdmr_num) +{ + int i; + + /* + * Initialize TDMRs one-by-one for simplicity, though the TDX + * architecture does allow different TDMRs to be initialized in + * parallel on multiple CPUs. Parallel initialization could + * be added later when the time spent in the serialized scheme + * becomes a real concern. + */ + for (i = 0; i < tdmr_num; i++) { + int ret; + + ret = init_tdmr(tdmr_array_entry(tdmr_array, i)); + if (ret) + return ret; + } + + return 0; +} + /* * Detect and initialize the TDX module. * @@ -1172,11 +1231,11 @@ static int init_tdx_module(void) if (ret) goto out_free_pamts; - /* - * Return -EINVAL until all steps of TDX module initialization - * process are done. - */ - ret = -EINVAL; + /* Initialize TDMRs to complete the TDX module initialization */ + ret = init_tdmrs(tdmr_array, tdmr_num); + if (ret) + goto out_free_pamts; + out_free_pamts: if (ret) { /* diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 768d097412ab..891691b1ea50 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -19,6 +19,7 @@ #define TDH_SYS_INFO 32 #define TDH_SYS_INIT 33 #define TDH_SYS_LP_INIT 35 +#define TDH_SYS_TDMR_INIT 36 #define TDH_SYS_LP_SHUTDOWN 44 #define TDH_SYS_CONFIG 45