> +struct tdmr_info_list { > + struct tdmr_info *first_tdmr; This is named badly. This is really a pointer to an array. While it _does_ of course point to the first member of the array, the naming should make it clear that there are multiple tdmr_infos here. > + int tdmr_sz; > + int max_tdmrs; > + int nr_tdmrs; /* Actual number of TDMRs */ > +}; This 'tdmr_info_list's is declared in an unfortunate place. I thought the tdmr_size_single() function below was related to it. Also, tdmr_sz and max_tdmrs can both be derived from 'sysinfo'. Do they really need to be stored here? If so, I think I'd probably do something like this with the structure: struct tdmr_info_list { struct tdmr_info *tdmrs; int nr_consumed_tdmrs; // How many @tdmrs are in use /* Metadata for freeing this structure: */ int tdmr_sz; // Size of one 'tdmr_info' (has a flex array) int max_tdmrs; // How many @tdmrs are allocated }; Modulo whataver folks are doing for comments these days. > +/* 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->first_tdmr = tdmr_array; > + /* ^ probably missing whitepsace before the comment > + * 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_tdmrs = 0; > + > + return 0; > +} > + > +static void free_tdmr_list(struct tdmr_info_list *tdmr_list) > +{ > + free_pages_exact(tdmr_list->first_tdmr, > + 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) > { > /* > @@ -358,6 +439,7 @@ static int init_tdx_module(void) > TDSYSINFO_STRUCT_SIZE, TDSYSINFO_STRUCT_ALIGNMENT); > struct cmr_info cmr_array[MAX_CMRS] __aligned(CMR_INFO_ARRAY_ALIGNMENT); > struct tdsysinfo_struct *sysinfo = &PADDED_STRUCT(tdsysinfo); > + struct tdmr_info_list tdmr_list; > int ret; > > ret = tdx_get_sysinfo(sysinfo, cmr_array); > @@ -380,11 +462,19 @@ static int init_tdx_module(void) > if (ret) > goto out; > > + /* Allocate enough space for constructing TDMRs */ > + ret = alloc_tdmr_list(&tdmr_list, sysinfo); > + if (ret) > + goto out_free_tdx_mem; > + > + /* Cover all TDX-usable memory regions in TDMRs */ > + ret = construct_tdmrs(&tdx_memlist, &tdmr_list, sysinfo); > + if (ret) > + goto out_free_tdmrs; > + > /* > * TODO: > * > - * - Construct a list of TDMRs to cover all TDX-usable memory > - * regions. > * - Pick up one TDX private KeyID as the global KeyID. > * - Configure the TDMRs and the global KeyID to the TDX module. > * - Configure the global KeyID on all packages. > @@ -393,6 +483,16 @@ static int init_tdx_module(void) > * Return error before all steps are done. > */ > ret = -EINVAL; > +out_free_tdmrs: > + /* > + * Free the space for the TDMRs no matter the initialization is > + * successful or not. They are not needed anymore after the > + * module initialization. > + */ > + free_tdmr_list(&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 6d32f62e4182..d0c762f1a94c 100644 > --- a/arch/x86/virt/vmx/tdx/tdx.h > +++ b/arch/x86/virt/vmx/tdx/tdx.h > @@ -90,6 +90,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!