Message ID | e01bbbc3ff4611adea84df683d83664714cd200f.1687784645.git.kai.huang@intel.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | TDX host kernel support | expand |
On Tue, Jun 27, 2023 at 02:12:46AM +1200, Kai Huang wrote: > After the global KeyID has been configured on all packages, initialize > all TDMRs to make all TDX-usable memory regions that are passed to the > TDX module become usable. > > This is the last step of initializing the TDX module. > > Initializing TDMRs can be time consuming on large memory systems as it > involves initializing all metadata entries for all pages that can be > used by TDX guests. Initializing different TDMRs can be parallelized. > For now to keep it simple, just initialize all TDMRs one by one. It can > be enhanced in the future. Reviewed-by: Yuan Yao <yuan.yao@intel.com> > > Signed-off-by: Kai Huang <kai.huang@intel.com> > Reviewed-by: Isaku Yamahata <isaku.yamahata@intel.com> > Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> > --- > > v11 -> v12: > - Added Kirill's tag > > v10 -> v11: > - No update > > v9 -> v10: > - Code change due to change static 'tdx_tdmr_list' to local 'tdmr_list'. > > v8 -> v9: > - Improved changlog to explain why initializing TDMRs can take long > time (Dave). > - Improved comments around 'next-to-initialize' address (Dave). > > v7 -> v8: (Dave) > - Changelog: > - explicitly call out this is the last step of TDX module initialization. > - Trimed down changelog by removing SEAMCALL name and details. > - Removed/trimmed down unnecessary comments. > - Other changes due to 'struct tdmr_info_list'. > > v6 -> v7: > - Removed need_resched() check. -- Andi. > > > --- > arch/x86/virt/vmx/tdx/tdx.c | 60 ++++++++++++++++++++++++++++++++----- > arch/x86/virt/vmx/tdx/tdx.h | 1 + > 2 files changed, 53 insertions(+), 8 deletions(-) > > diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c > index f5d4dbc11aee..52b7267ea226 100644 > --- a/arch/x86/virt/vmx/tdx/tdx.c > +++ b/arch/x86/virt/vmx/tdx/tdx.c > @@ -994,6 +994,56 @@ static int config_global_keyid(void) > return ret; > } > > +static int init_tdmr(struct tdmr_info *tdmr) > +{ > + u64 next; > + > + /* > + * 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. > + */ > + do { > + struct tdx_module_output out; > + int ret; > + > + /* All 0's are unused parameters, they mean nothing. */ > + 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.INIT did not fully complete and > + * should be retried. > + */ > + next = out.rdx; > + cond_resched(); > + /* Keep making SEAMCALLs until the TDMR is done */ > + } while (next < tdmr->base + tdmr->size); > + > + return 0; > +} > + > +static int init_tdmrs(struct tdmr_info_list *tdmr_list) > +{ > + int i; > + > + /* > + * This operation is costly. It can be parallelized, > + * but keep it simple for now. > + */ > + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { > + int ret; > + > + ret = init_tdmr(tdmr_entry(tdmr_list, i)); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > static int init_tdx_module(void) > { > struct tdsysinfo_struct *sysinfo; > @@ -1067,14 +1117,8 @@ static int init_tdx_module(void) > if (ret) > goto out_reset_pamts; > > - /* > - * TODO: > - * > - * - Initialize all TDMRs. > - * > - * Return error before all steps are done. > - */ > - ret = -EINVAL; > + /* Initialize TDMRs to complete the TDX module initialization */ > + ret = init_tdmrs(&tdmr_list); > out_reset_pamts: > if (ret) { > /* > diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h > index a0438513bec0..f6b4e153890d 100644 > --- a/arch/x86/virt/vmx/tdx/tdx.h > +++ b/arch/x86/virt/vmx/tdx/tdx.h > @@ -25,6 +25,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_CONFIG 45 > > struct cmr_info { > -- > 2.40.1 >
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index f5d4dbc11aee..52b7267ea226 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -994,6 +994,56 @@ static int config_global_keyid(void) return ret; } +static int init_tdmr(struct tdmr_info *tdmr) +{ + u64 next; + + /* + * 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. + */ + do { + struct tdx_module_output out; + int ret; + + /* All 0's are unused parameters, they mean nothing. */ + 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.INIT did not fully complete and + * should be retried. + */ + next = out.rdx; + cond_resched(); + /* Keep making SEAMCALLs until the TDMR is done */ + } while (next < tdmr->base + tdmr->size); + + return 0; +} + +static int init_tdmrs(struct tdmr_info_list *tdmr_list) +{ + int i; + + /* + * This operation is costly. It can be parallelized, + * but keep it simple for now. + */ + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + int ret; + + ret = init_tdmr(tdmr_entry(tdmr_list, i)); + if (ret) + return ret; + } + + return 0; +} + static int init_tdx_module(void) { struct tdsysinfo_struct *sysinfo; @@ -1067,14 +1117,8 @@ static int init_tdx_module(void) if (ret) goto out_reset_pamts; - /* - * TODO: - * - * - Initialize all TDMRs. - * - * Return error before all steps are done. - */ - ret = -EINVAL; + /* Initialize TDMRs to complete the TDX module initialization */ + ret = init_tdmrs(&tdmr_list); out_reset_pamts: if (ret) { /* diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index a0438513bec0..f6b4e153890d 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -25,6 +25,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_CONFIG 45 struct cmr_info {