Message ID | f9148e67e968d7aed4707b67ea9b1aa761401255.1685887183.git.kai.huang@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | TDX host kernel support | expand |
On 6/4/23 07:27, Kai Huang wrote: > Constructing the list of TDMRs consists below steps: <grumble> <grumble> grammar <grumble> <grumble> Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
On 6/4/23 07:27, Kai Huang wrote: > +struct tdmr_info_list { > + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ > + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ I'm looking back here after seeing the weird cast in the next patch. Why is this a void* instead of a _real_ type?
On Wed, 2023-06-07 at 08:57 -0700, Dave Hansen wrote: > On 6/4/23 07:27, Kai Huang wrote: > > +struct tdmr_info_list { > > + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ > > + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ > > I'm looking back here after seeing the weird cast in the next patch. > > Why is this a void* instead of a _real_ type? I followed your suggestion in v8: https://lore.kernel.org/linux-mm/725de6e9-e468-48ef-3bae-1e8a1b7ef0f7@intel.com/ I quoted the relevant part here: > +/* Get the TDMR from the list at the given index. */ > +static struct tdmr_info *tdmr_entry(struct tdmr_info_list *tdmr_list, > + int idx) > +{ > + return (struct tdmr_info *)((unsigned long)tdmr_list->first_tdmr + > + tdmr_list->tdmr_sz * idx); > +} I think that's more complicated and has more casting than necessary. This looks nicer: int tdmr_info_offset = tdmr_list->tdmr_sz * idx; return (void *)tdmr_list->first_tdmr + tdmr_info_offset; Also, it might even be worth keeping ->first_tdmr as a void*. It isn't a real C array and keeping it as void* would keep anyone from doing: tdmr_foo = tdmr_list->first_tdmr[foo];
On Mon, Jun 05, 2023 at 02:27:23AM +1200, Kai Huang wrote: > @@ -50,6 +51,8 @@ static DEFINE_MUTEX(tdx_module_lock); > /* All TDX-usable memory regions. Protected by mem_hotplug_lock. */ > static LIST_HEAD(tdx_memlist); > > +static struct tdmr_info_list tdx_tdmr_list; > + > /* > * Wrapper of __seamcall() to convert SEAMCALL leaf function error code > * to kernel error code. @seamcall_ret and @out contain the SEAMCALL The name is misleading. It is not list, it is an array. ... > @@ -112,6 +135,15 @@ struct tdx_memblock { > unsigned long end_pfn; > }; > > +struct tdmr_info_list { > + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ > + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ > + > + /* Metadata for finding target 'tdmr_info' and freeing @tdmrs */ > + int tdmr_sz; /* Size of one 'tdmr_info' */ > + int max_tdmrs; /* How many 'tdmr_info's are allocated */ > +}; > + > struct tdx_module_output; > u64 __seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, > struct tdx_module_output *out); Otherwise, looks okay. Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
On Fri, 2023-06-09 at 01:52 +0300, kirill.shutemov@linux.intel.com wrote: > On Mon, Jun 05, 2023 at 02:27:23AM +1200, Kai Huang wrote: > > @@ -50,6 +51,8 @@ static DEFINE_MUTEX(tdx_module_lock); > > /* All TDX-usable memory regions. Protected by mem_hotplug_lock. */ > > static LIST_HEAD(tdx_memlist); > > > > +static struct tdmr_info_list tdx_tdmr_list; > > + > > /* > > * Wrapper of __seamcall() to convert SEAMCALL leaf function error code > > * to kernel error code. @seamcall_ret and @out contain the SEAMCALL > > The name is misleading. It is not list, it is an array. I followed Dave's suggestion in v7: https://lore.kernel.org/lkml/d84ad1d2-83f9-dab5-5639-8d71f382e3ff@intel.com/ Quote the relevant part here: " > +static struct tdmr_info *tdmr_array_entry(struct tdmr_info *tdmr_array, > + int idx) > +{ > + return (struct tdmr_info *)((unsigned long)tdmr_array + > + cal_tdmr_size() * idx); > +} FWIW, I think it's probably a bad idea to have 'struct tdmr_info *' types floating around since: tmdr_info_array[0] works, but: tmdr_info_array[1] will blow up in your face. It would almost make sense to have struct tdmr_info_list { struct tdmr_info *first_tdmr; } and then pass around pointers to the 'struct tdmr_info_list'. Maybe that's overkill, but it is kinda silly to call something an array if [] doesn't work on it. " Personally I think it's also fine to use 'list' (e.g., we can also interpret the name from "English language"'s perspective). Hi Dave, Should I change the name to "tdmr_info_array"? > > > ... > > > @@ -112,6 +135,15 @@ struct tdx_memblock { > > unsigned long end_pfn; > > }; > > > > +struct tdmr_info_list { > > + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ > > + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ > > + > > + /* Metadata for finding target 'tdmr_info' and freeing @tdmrs */ > > + int tdmr_sz; /* Size of one 'tdmr_info' */ > > + int max_tdmrs; /* How many 'tdmr_info's are allocated */ > > +}; > > + > > struct tdx_module_output; > > u64 __seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, > > struct tdx_module_output *out); > > Otherwise, looks okay. > > Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> >
On 6/11/23 19:21, Huang, Kai wrote:
> Should I change the name to "tdmr_info_array"?
If foo[bar] works on it, then it's an array. If not, then it's not an
array.
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 1504023f7f63..7a20c72361e7 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -24,6 +24,7 @@ #include <linux/minmax.h> #include <linux/sizes.h> #include <linux/pfn.h> +#include <linux/align.h> #include <asm/msr-index.h> #include <asm/msr.h> #include <asm/archrandom.h> @@ -50,6 +51,8 @@ static DEFINE_MUTEX(tdx_module_lock); /* All TDX-usable memory regions. Protected by mem_hotplug_lock. */ static LIST_HEAD(tdx_memlist); +static struct tdmr_info_list tdx_tdmr_list; + /* * Wrapper of __seamcall() to convert SEAMCALL leaf function error code * to kernel error code. @seamcall_ret and @out contain the SEAMCALL @@ -329,6 +332,80 @@ static int build_tdx_memlist(struct list_head *tmb_list) return ret; } +/* Calculate the actual TDMR size */ +static int tdmr_size_single(u16 max_reserved_per_tdmr) +{ + int tdmr_sz; + + /* + * The actual size of TDMR depends on the maximum + * number of reserved areas. + */ + tdmr_sz = sizeof(struct tdmr_info); + tdmr_sz += sizeof(struct tdmr_reserved_area) * max_reserved_per_tdmr; + + return ALIGN(tdmr_sz, TDMR_INFO_ALIGNMENT); +} + +static int alloc_tdmr_list(struct tdmr_info_list *tdmr_list, + struct tdsysinfo_struct *sysinfo) +{ + size_t tdmr_sz, tdmr_array_sz; + void *tdmr_array; + + tdmr_sz = tdmr_size_single(sysinfo->max_reserved_per_tdmr); + tdmr_array_sz = tdmr_sz * sysinfo->max_tdmrs; + + /* + * To keep things simple, allocate all TDMRs together. + * The buffer needs to be physically contiguous to make + * sure each TDMR is physically contiguous. + */ + tdmr_array = alloc_pages_exact(tdmr_array_sz, + GFP_KERNEL | __GFP_ZERO); + if (!tdmr_array) + return -ENOMEM; + + tdmr_list->tdmrs = tdmr_array; + + /* + * Keep the size of TDMR to find the target TDMR + * at a given index in the TDMR list. + */ + tdmr_list->tdmr_sz = tdmr_sz; + tdmr_list->max_tdmrs = sysinfo->max_tdmrs; + tdmr_list->nr_consumed_tdmrs = 0; + + return 0; +} + +static void free_tdmr_list(struct tdmr_info_list *tdmr_list) +{ + free_pages_exact(tdmr_list->tdmrs, + tdmr_list->max_tdmrs * tdmr_list->tdmr_sz); +} + +/* + * Construct a list of TDMRs on the preallocated space in @tdmr_list + * to cover all TDX memory regions in @tmb_list based on the TDX module + * information in @sysinfo. + */ +static int construct_tdmrs(struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list, + struct tdsysinfo_struct *sysinfo) +{ + /* + * TODO: + * + * - Fill out TDMRs to cover all TDX memory regions. + * - Allocate and set up PAMTs for each TDMR. + * - Designate reserved areas for each TDMR. + * + * Return -EINVAL until constructing TDMRs is done + */ + return -EINVAL; +} + static int init_tdx_module(void) { static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, @@ -358,11 +435,19 @@ static int init_tdx_module(void) if (ret) goto out; + /* Allocate enough space for constructing TDMRs */ + ret = alloc_tdmr_list(&tdx_tdmr_list, sysinfo); + if (ret) + goto out_free_tdx_mem; + + /* Cover all TDX-usable memory regions in TDMRs */ + ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, sysinfo); + if (ret) + goto out_free_tdmrs; + /* * TODO: * - * - Construct a list of "TD Memory Regions" (TDMRs) to cover - * all TDX-usable memory regions. * - Configure the TDMRs and the global KeyID to the TDX module. * - Configure the global KeyID on all packages. * - Initialize all TDMRs. @@ -370,6 +455,12 @@ static int init_tdx_module(void) * Return error before all steps are done. */ ret = -EINVAL; +out_free_tdmrs: + if (ret) + free_tdmr_list(&tdx_tdmr_list); +out_free_tdx_mem: + if (ret) + free_tdx_memlist(&tdx_memlist); out: /* * @tdx_memlist is written here and read at memory hotplug time. diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 4b6fc0d8b420..c20848e76469 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -94,6 +94,29 @@ struct tdsysinfo_struct { DECLARE_FLEX_ARRAY(struct cpuid_config, cpuid_configs); } __packed; +struct tdmr_reserved_area { + u64 offset; + u64 size; +} __packed; + +#define TDMR_INFO_ALIGNMENT 512 + +struct tdmr_info { + u64 base; + u64 size; + u64 pamt_1g_base; + u64 pamt_1g_size; + u64 pamt_2m_base; + u64 pamt_2m_size; + u64 pamt_4k_base; + u64 pamt_4k_size; + /* + * Actual number of reserved areas depends on + * 'struct tdsysinfo_struct'::max_reserved_per_tdmr. + */ + DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas); +} __packed __aligned(TDMR_INFO_ALIGNMENT); + /* * Do not put any hardware-defined TDX structure representations below * this comment! @@ -112,6 +135,15 @@ struct tdx_memblock { unsigned long end_pfn; }; +struct tdmr_info_list { + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ + + /* Metadata for finding target 'tdmr_info' and freeing @tdmrs */ + int tdmr_sz; /* Size of one 'tdmr_info' */ + int max_tdmrs; /* How many 'tdmr_info's are allocated */ +}; + struct tdx_module_output; u64 __seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, struct tdx_module_output *out);