From patchwork Tue Aug 27 07:14:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778993 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB6EB17279C; Tue, 27 Aug 2024 07:14:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742890; cv=none; b=oTKIKi+tLUvp8mUOt5Th/oAd3tZPMRciFdFlUJbcB02oJkIP0LyfNRCIaXZGriJHgcLz0PHU5Pdga1f52R+yFockMkRW4Y2G7hz41EogSwFNTmJxeKcnawaKm6WqjT9brtoLiODw492Hz3rvhkWsUfDKUNCRZjQB4z6dF8iuMSw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742890; c=relaxed/simple; bh=npUkGw6R8W7ILeCfngiPPW9+eVLpOoHJ4+AYqYuTe4o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bZTxRcfCv4HdsXSjZdvSLVdnQELwUn/4Uf4gs4u5tAdmFtA0Z0/mCAPposjbuHK2yLuO2ileXdkbqrIQzt1i/MwzbMv5EJKzkxk2oqUPlDEa4b2/W44nTeIV+Orkr80wUJ6eFXlRJkQ9KfCyE0HiU7+GrgsPIL03/cmHSsO6Brc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Ilfet7EV; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Ilfet7EV" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742889; x=1756278889; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=npUkGw6R8W7ILeCfngiPPW9+eVLpOoHJ4+AYqYuTe4o=; b=Ilfet7EV2Te1DK6VIvrjNjUb87fP5e4MuwSatltFGssUvkDO3Spu+yLz 1ihEkooVazV491Qyl0urZYMjbiP5QDsqL5gpMG/9zsML/mgs3hWu8tex1 pMiUzd6j8dPYfOuIASSGMOmWTKON8ihHfWdy4en9E6ThIMBhZH8QjIv1+ 3kZK8KDBQsbd7hUgYjTjkinGrIAjO5I1HdZ+NDmWvjMkuLZg7Ho+jDEUi FP76IHuKRSgBrlcC53t3jJN5uy8OmUKLfyhjg+H0Fk6ZJXRjryzJUx7aR Wn1lPVDsX9FMRMbMHn/0jg0AqQB0k4yadCGnykxpB9jKlkQIOivz/h1sd g==; X-CSE-ConnectionGUID: qE+Nr27oSGukC5CRIOVerg== X-CSE-MsgGUID: QRd6AvdSQWGzzlRPVIudIA== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575822" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575822" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:49 -0700 X-CSE-ConnectionGUID: N0USew8yRRaETuRQ+ES5PQ== X-CSE-MsgGUID: UTDj1RixQ3ynUzRblr4bTA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092545" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:43 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 1/8] x86/virt/tdx: Rename 'struct tdx_tdmr_sysinfo' to reflect the spec better Date: Tue, 27 Aug 2024 19:14:23 +1200 Message-ID: X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The TDX module provides a set of "global metadata fields". They report things like TDX module version, supported features, and fields related to create/run TDX guests and so on. TDX organizes those metadata fields by "Class"es based on the meaning of those fields. E.g., for now the kernel only reads "TD Memory Region" (TDMR) related fields for module initialization. Those fields are defined under class "TDMR Info". There are both immediate needs to read more metadata fields for module initialization and near-future needs for other kernel components like KVM to run TDX guests. To meet all those requirements, the idea is the TDX host core-kernel to provide a centralized, canonical, and read-only structure for the global metadata that comes out from the TDX module for all kernel components to use. More specifically, the target is to end up with something like: struct tdx_sys_info { struct tdx_sys_info_classA a; struct tdx_sys_info_classB b; ... }; Currently the kernel organizes all fields under "TDMR Info" class in 'struct tdx_tdmr_sysinfo'. To prepare for the above target, rename the structure to 'struct tdx_sys_info_tdmr' to follow the class name better. No functional change intended. Signed-off-by: Kai Huang Reviewed-by: Dan Williams --- v2 -> v3: - Split out as a separate patch and place it at beginning: https://lore.kernel.org/kvm/cover.1721186590.git.kai.huang@intel.com/T/#m8fec7c429242d640cf5e756eb68e3b822e6dff8b - Rename to 'struct tdx_sys_info_tdmr': https://lore.kernel.org/kvm/cover.1721186590.git.kai.huang@intel.com/T/#md73dd9b02a492acf4a6facae63e8d030e320967d https://lore.kernel.org/kvm/cover.1721186590.git.kai.huang@intel.com/T/#m8fec7c429242d640cf5e756eb68e3b822e6dff8b --- arch/x86/virt/vmx/tdx/tdx.c | 36 ++++++++++++++++++------------------ arch/x86/virt/vmx/tdx/tdx.h | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 4e2b2e2ac9f9..e979bf442929 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -272,7 +272,7 @@ static int read_sys_metadata_field(u64 field_id, u64 *data) static int read_sys_metadata_field16(u64 field_id, int offset, - struct tdx_tdmr_sysinfo *ts) + struct tdx_sys_info_tdmr *ts) { u16 *ts_member = ((void *)ts) + offset; u64 tmp; @@ -298,9 +298,9 @@ struct field_mapping { #define TD_SYSINFO_MAP(_field_id, _offset) \ { .field_id = MD_FIELD_ID_##_field_id, \ - .offset = offsetof(struct tdx_tdmr_sysinfo, _offset) } + .offset = offsetof(struct tdx_sys_info_tdmr, _offset) } -/* Map TD_SYSINFO fields into 'struct tdx_tdmr_sysinfo': */ +/* Map TD_SYSINFO fields into 'struct tdx_sys_info_tdmr': */ static const struct field_mapping fields[] = { TD_SYSINFO_MAP(MAX_TDMRS, max_tdmrs), TD_SYSINFO_MAP(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr), @@ -309,16 +309,16 @@ static const struct field_mapping fields[] = { TD_SYSINFO_MAP(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]), }; -static int get_tdx_tdmr_sysinfo(struct tdx_tdmr_sysinfo *tdmr_sysinfo) +static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) { int ret; int i; - /* Populate 'tdmr_sysinfo' fields using the mapping structure above: */ + /* Populate 'sysinfo_tdmr' fields using the mapping structure above: */ for (i = 0; i < ARRAY_SIZE(fields); i++) { ret = read_sys_metadata_field16(fields[i].field_id, fields[i].offset, - tdmr_sysinfo); + sysinfo_tdmr); if (ret) return ret; } @@ -342,13 +342,13 @@ static int tdmr_size_single(u16 max_reserved_per_tdmr) } static int alloc_tdmr_list(struct tdmr_info_list *tdmr_list, - struct tdx_tdmr_sysinfo *tdmr_sysinfo) + struct tdx_sys_info_tdmr *sysinfo_tdmr) { size_t tdmr_sz, tdmr_array_sz; void *tdmr_array; - tdmr_sz = tdmr_size_single(tdmr_sysinfo->max_reserved_per_tdmr); - tdmr_array_sz = tdmr_sz * tdmr_sysinfo->max_tdmrs; + tdmr_sz = tdmr_size_single(sysinfo_tdmr->max_reserved_per_tdmr); + tdmr_array_sz = tdmr_sz * sysinfo_tdmr->max_tdmrs; /* * To keep things simple, allocate all TDMRs together. @@ -367,7 +367,7 @@ static int alloc_tdmr_list(struct tdmr_info_list *tdmr_list, * at a given index in the TDMR list. */ tdmr_list->tdmr_sz = tdmr_sz; - tdmr_list->max_tdmrs = tdmr_sysinfo->max_tdmrs; + tdmr_list->max_tdmrs = sysinfo_tdmr->max_tdmrs; tdmr_list->nr_consumed_tdmrs = 0; return 0; @@ -921,11 +921,11 @@ static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, /* * 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 - * TDMR global information in @tdmr_sysinfo. + * TDMR global information in @sysinfo_tdmr. */ static int construct_tdmrs(struct list_head *tmb_list, struct tdmr_info_list *tdmr_list, - struct tdx_tdmr_sysinfo *tdmr_sysinfo) + struct tdx_sys_info_tdmr *sysinfo_tdmr) { int ret; @@ -934,12 +934,12 @@ static int construct_tdmrs(struct list_head *tmb_list, return ret; ret = tdmrs_set_up_pamt_all(tdmr_list, tmb_list, - tdmr_sysinfo->pamt_entry_size); + sysinfo_tdmr->pamt_entry_size); if (ret) return ret; ret = tdmrs_populate_rsvd_areas_all(tdmr_list, tmb_list, - tdmr_sysinfo->max_reserved_per_tdmr); + sysinfo_tdmr->max_reserved_per_tdmr); if (ret) tdmrs_free_pamt_all(tdmr_list); @@ -1098,7 +1098,7 @@ static int init_tdmrs(struct tdmr_info_list *tdmr_list) static int init_tdx_module(void) { - struct tdx_tdmr_sysinfo tdmr_sysinfo; + struct tdx_sys_info_tdmr sysinfo_tdmr; int ret; /* @@ -1117,17 +1117,17 @@ static int init_tdx_module(void) if (ret) goto out_put_tdxmem; - ret = get_tdx_tdmr_sysinfo(&tdmr_sysinfo); + ret = get_tdx_sys_info_tdmr(&sysinfo_tdmr); if (ret) goto err_free_tdxmem; /* Allocate enough space for constructing TDMRs */ - ret = alloc_tdmr_list(&tdx_tdmr_list, &tdmr_sysinfo); + ret = alloc_tdmr_list(&tdx_tdmr_list, &sysinfo_tdmr); if (ret) goto err_free_tdxmem; /* Cover all TDX-usable memory regions in TDMRs */ - ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &tdmr_sysinfo); + ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &sysinfo_tdmr); if (ret) goto err_free_tdmrs; diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index b701f69485d3..148f9b4d1140 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -100,7 +100,7 @@ struct tdx_memblock { }; /* "TDMR info" part of "Global Scope Metadata" for constructing TDMRs */ -struct tdx_tdmr_sysinfo { +struct tdx_sys_info_tdmr { u16 max_tdmrs; u16 max_reserved_per_tdmr; u16 pamt_entry_size[TDX_PS_NR]; From patchwork Tue Aug 27 07:14:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778994 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D9B2176AD8; Tue, 27 Aug 2024 07:14:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742895; cv=none; b=W73A4qUdVi6EZAAabuw2X6C1EIxrd4IoKEIHqGBS8Y6NKV22UVtD07is/IeZAL1J55EG6pYJpit/UMTKoACDugXYLwUTykN91xlGddCbVfUVNyyvKq8+JTxwW3GnfIsvc+ncKWdQXiO3d2Pe9YyAk3HbTmnSmHYXOdvTvytt+To= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742895; c=relaxed/simple; bh=iFLI9opUKCsmP49NeCvv84rUP9mlus1wfcrUWKWlI3k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mBEYIg4+p9VVxvAxJ4AYzX4AR9Tzfb7entUaMZDQJ3JCRAl1mAJbNWcv9LbQ13aL39P2mTMdFS4bF7JczwXuLMh05qLHmrlGgP51WumncE+jkgGj7b11j2CfEGUdWcT2/pJP/yqBtLTiEfVBt9zx9WsAaTM97jBAIvV7k4CfcmU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=TKU95QZX; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="TKU95QZX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742893; x=1756278893; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iFLI9opUKCsmP49NeCvv84rUP9mlus1wfcrUWKWlI3k=; b=TKU95QZXB1eMW4Fn4RBCX3FyLYE79amH9uZYYYhFEgW+veQfuTCfszDu XKX1zX2en49hd+cx6Di0yUhTJ4241OX7YWqmsf0Kon2UFTpu5WuYiD9f/ P4eQlyzjS9j7CCwIAgJfAuF9iNxNZ5141hR+oVlL/FsZaat83W9YCt+Rx WLeDzMrep1VDb84AMIw+vWj3u1x9VAu51nTD+OS7UVNQ4f7WkIKGoUIFH CpW5nh4E6442U9kXQjRCNbirOSMbzYP7XpfUpkiI2fU76tFhHF3oAmZ6i X2e6Bgc9rvjfQA07csjSxxRlrC8m0b4CPU0lNiJIsDNQYmcuf23bVD8Lq Q==; X-CSE-ConnectionGUID: ParDVjRVS06E8jMVRKltCA== X-CSE-MsgGUID: G1WC0tuOS8KWX8xwgi0Vfw== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575845" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575845" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:53 -0700 X-CSE-ConnectionGUID: 9BBXF/xcQ9+ch2c5QL7FaQ== X-CSE-MsgGUID: qpKaiLsLSEemSRikRiTTpw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092554" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:48 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 2/8] x86/virt/tdx: Remove 'struct field_mapping' and implement TD_SYSINFO_MAP() macro Date: Tue, 27 Aug 2024 19:14:24 +1200 Message-ID: <9eb6b2e3577be66ea2f711e37141ca021bf0159b.1724741926.git.kai.huang@intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 TL;DR: Remove the 'struct field_mapping' structure and use another way to implement the TD_SYSINFO_MAP() macro to improve the current metadata reading code, e.g., switching to use build-time check for metadata field size over the existing runtime check. The TDX module provides a set of "global metadata fields". They report things like TDX module version, supported features, and fields related to create/run TDX guests and so on. For now the kernel only reads "TD Memory Region" (TDMR) related global metadata fields, and all of those fields are organized in one structure. The kernel currently uses 'struct field_mapping' to facilitate reading multiple metadata fields into one structure. The 'struct field_mapping' records the mapping between the field ID and the offset of the structure to fill out. The kernel initializes an array of 'struct field_mapping' for each structure member (using the TD_SYSINFO_MAP() macro) and then reads all metadata fields in a loop using that array. Currently the kernel only reads TDMR related metadata fields into one structure, and the function to read one metadata field takes the pointer of that structure and the offset: static int read_sys_metadata_field16(u64 field_id, int offset, struct tdx_sys_info_tdmr *ts) {...} Future changes will need to read more metadata fields into different structures. To support this the above function will need to be changed to take 'void *': static int read_sys_metadata_field16(u64 field_id, int offset, void *stbuf) {...} This approach loses type-safety, as Dan suggested. A better way is to make it be .. static int read_sys_metadata_field16(u64 field_id, u16 *val) {...} .. and let the caller calculate the buffer in a type-safe way [1]. Also, the using of the 'struct field_mapping' loses the ability to be able to do build-time check about the metadata field size (encoded in the field ID) due to the field ID is "indirectly" initialized to the 'struct field_mapping' and passed to the function to read. Thus the current code uses runtime check instead. Dan suggested to remove the 'struct field_mapping', unroll the loop, skip the array, and call the read_sys_metadata_field16() directly with build-time check [1][2]. And to improve the readability, reimplement the TD_SYSINFO_MAP() [3]. The new TD_SYSINFO_MAP() isn't perfect. It requires the function that uses it to define a local variable @ret to carry the error code and set the initial value to 0. It also hard-codes the variable name of the structure pointer used in the function. But overall the pros of this approach beat the cons. Link: https://lore.kernel.org/kvm/a107b067-861d-43f4-86b5-29271cb93dad@intel.com/T/#m7cfb3c146214d94b24e978eeb8708d92c0b14ac6 [1] Link: https://lore.kernel.org/kvm/a107b067-861d-43f4-86b5-29271cb93dad@intel.com/T/#mbe65f0903ff7835bc418a907f0d02d7a9e0b78be [2] Link: https://lore.kernel.org/kvm/a107b067-861d-43f4-86b5-29271cb93dad@intel.com/T/#m80cde5e6504b3af74d933ea0cbfc3ca9d24697d3 [3] Suggested-by: Dan Williams Signed-off-by: Kai Huang --- v2 -> v3: - Remove 'struct field_mapping' and reimplement TD_SYSINFO_MAP(). --- arch/x86/virt/vmx/tdx/tdx.c | 57 ++++++++++++++----------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index e979bf442929..7e75c1b10838 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -270,60 +270,45 @@ static int read_sys_metadata_field(u64 field_id, u64 *data) return 0; } -static int read_sys_metadata_field16(u64 field_id, - int offset, - struct tdx_sys_info_tdmr *ts) +static int read_sys_metadata_field16(u64 field_id, u16 *val) { - u16 *ts_member = ((void *)ts) + offset; u64 tmp; int ret; - if (WARN_ON_ONCE(MD_FIELD_ID_ELE_SIZE_CODE(field_id) != - MD_FIELD_ID_ELE_SIZE_16BIT)) - return -EINVAL; + BUILD_BUG_ON(MD_FIELD_ID_ELE_SIZE_CODE(field_id) != + MD_FIELD_ID_ELE_SIZE_16BIT); ret = read_sys_metadata_field(field_id, &tmp); if (ret) return ret; - *ts_member = tmp; + *val = tmp; return 0; } -struct field_mapping { - u64 field_id; - int offset; -}; - -#define TD_SYSINFO_MAP(_field_id, _offset) \ - { .field_id = MD_FIELD_ID_##_field_id, \ - .offset = offsetof(struct tdx_sys_info_tdmr, _offset) } - -/* Map TD_SYSINFO fields into 'struct tdx_sys_info_tdmr': */ -static const struct field_mapping fields[] = { - TD_SYSINFO_MAP(MAX_TDMRS, max_tdmrs), - TD_SYSINFO_MAP(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr), - TD_SYSINFO_MAP(PAMT_4K_ENTRY_SIZE, pamt_entry_size[TDX_PS_4K]), - TD_SYSINFO_MAP(PAMT_2M_ENTRY_SIZE, pamt_entry_size[TDX_PS_2M]), - TD_SYSINFO_MAP(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]), -}; +/* + * Assumes locally defined @ret and @sysinfo_tdmr to convey the error + * code and the 'struct tdx_sys_info_tdmr' instance to fill out. + */ +#define TD_SYSINFO_MAP(_field_id, _member) \ + ({ \ + if (!ret) \ + ret = read_sys_metadata_field16(MD_FIELD_ID_##_field_id, \ + &sysinfo_tdmr->_member); \ + }) static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) { - int ret; - int i; + int ret = 0; - /* Populate 'sysinfo_tdmr' fields using the mapping structure above: */ - for (i = 0; i < ARRAY_SIZE(fields); i++) { - ret = read_sys_metadata_field16(fields[i].field_id, - fields[i].offset, - sysinfo_tdmr); - if (ret) - return ret; - } + TD_SYSINFO_MAP(MAX_TDMRS, max_tdmrs); + TD_SYSINFO_MAP(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr); + TD_SYSINFO_MAP(PAMT_4K_ENTRY_SIZE, pamt_entry_size[TDX_PS_4K]); + TD_SYSINFO_MAP(PAMT_2M_ENTRY_SIZE, pamt_entry_size[TDX_PS_2M]); + TD_SYSINFO_MAP(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]); - return 0; + return ret; } /* Calculate the actual TDMR size */ From patchwork Tue Aug 27 07:14:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778995 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D0BF18BC0B; Tue, 27 Aug 2024 07:14:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742899; cv=none; b=c9KmkoVK0bUMW4OcZHIJJAvYDv0e2Oao9hRjSWataSBDOH30evVwNscMDtWBctArQrcQoxburH/c0AI0e8kOQYREafr1ylo56YSL5lol6WyFjM0RinqgRhGyhqpkCe5hk97tGgZD3aWXhgzA0iS2E+v4RyDYyXTO2ocfNxAF4i4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742899; c=relaxed/simple; bh=4xKIYmHCB/2TOsHERqmzFIZbnqrMLQF47LCBJ+7nB9Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B9BdSrJmcV2xCuwwQYS0SJAiwUS04YNAuNPBna3lh1EAlm0cLQB9Qb8amx8ztkQNyA4DL21SxoCrkbIiPE5157AlwT/JHPLRVjj6XACBkMfwmB8NL1irNZ8vCk+TupHknzqzToynEHIFu/3xiIrTbC18v1Ub0chCzI68B7KpyUE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=F1+Me+tR; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="F1+Me+tR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742898; x=1756278898; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4xKIYmHCB/2TOsHERqmzFIZbnqrMLQF47LCBJ+7nB9Q=; b=F1+Me+tRddD6shRhq1cfHW2/XquedKNEGNkEDPMh2wQONEitzgVmgX7V eDxqGNNHtg3nrbuB5fKHAvSX3bv/xFXajUcrWSIV2LQGCuPyovYM6B/h5 AYzUDOrHVfQHGgX+6/V+16gdYJ9ltEIJ/NdVBA3N2J91hzhuSDgO55cZ1 1HemLoh4pKX8TMKvyvitUB1T4RHsz69y1KTFFwbFN0qMJXFl2DeC9bEBP EHSrzaXwkrfRODmRg62YXhNqzYG7FMMgEXS++0qUP5YygQUrOrjENlfv1 pZkWALo/taz+VhfNiVVuwbaJvs6m2YNmhB0GCkZf2Kr6yk/GEMqFugXD+ Q==; X-CSE-ConnectionGUID: IMJ6tyrbRJKratnF9DAgNg== X-CSE-MsgGUID: 9KNFgBQ6T2u7sW+kJORlNg== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575855" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575855" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:57 -0700 X-CSE-ConnectionGUID: RpoSBTgSS7Gh1aKt4zBBFQ== X-CSE-MsgGUID: /RnOVXIeQKKdH0VtiHqUSw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092562" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:53 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 3/8] x86/virt/tdx: Prepare to support reading other global metadata fields Date: Tue, 27 Aug 2024 19:14:25 +1200 Message-ID: <0403cdb142b40b9838feeb222eb75a4831f6b46d.1724741926.git.kai.huang@intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The TDX module provides a set of "global metadata fields". They report things like TDX module version, supported features, and fields related to create/run TDX guests and so on. For now the kernel only reads "TD Memory Region" (TDMR) related fields for module initialization. There are both immediate needs to read more fields for module initialization and near-future needs for other kernel components like KVM to run TDX guests. will be organized in different structures depending on their meanings. For now the kernel only reads TDMR related fields. The TD_SYSINFO_MAP() macro hard-codes the 'struct tdx_sys_info_tdmr' instance name. To make it work with different instances of different structures, extend it to take the structure instance name as an argument. This also means the current code which uses TD_SYSINFO_MAP() must type 'struct tdx_sys_info_tdmr' instance name explicitly for each use. To make the code easier to read, add a wrapper TD_SYSINFO_MAP_TDMR_INFO() which hides the instance name. TDX also support 8/16/32/64 bits metadata field element sizes. For now all TDMR related fields are 16-bit long thus the kernel only has one helper: static int read_sys_metadata_field16(u64 field_id, u16 *val) {} Future changes will need to read more metadata fields with different element sizes. To make the code short, extend the helper to take a 'void *' buffer and the buffer size so it can work with all element sizes. Note in this way the helper loses the type safety and the build-time check inside the helper cannot work anymore because the compiler cannot determine the exact value of the buffer size. To resolve those, add a wrapper of the helper which only works with u8/u16/u32/u64 directly and do build-time check, where the compiler can easily know both the element size (from field ID) and the buffer size(using sizeof()), before calling the helper. An alternative option is to provide one helper for each element size: static int read_sys_metadata_field8(u64 field_id, u8 *val) {} static int read_sys_metadata_field16(u64 field_id, u16 *val) {} ... But this will result in duplicated code given those helpers will look exactly the same except for the type of buffer pointer. It's feasible to define a macro for the body of the helper and define one entry for each element size to reduce the code, but it is a little bit over-engineering. Signed-off-by: Kai Huang --- v2 -> v3: - Rename read_sys_metadata_field() to tdh_sys_rd() so the former can be used as the high level wrapper. Get rid of "stbuf_" prefix since people don't like it. - Rewrite after removing 'struct field_mapping' and reimplementing TD_SYSINFO_MAP(). --- arch/x86/virt/vmx/tdx/tdx.c | 45 +++++++++++++++++++++---------------- arch/x86/virt/vmx/tdx/tdx.h | 3 ++- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 7e75c1b10838..1cd9035c783f 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -250,7 +250,7 @@ static int build_tdx_memlist(struct list_head *tmb_list) return ret; } -static int read_sys_metadata_field(u64 field_id, u64 *data) +static int tdh_sys_rd(u64 field_id, u64 *data) { struct tdx_module_args args = {}; int ret; @@ -270,43 +270,50 @@ static int read_sys_metadata_field(u64 field_id, u64 *data) return 0; } -static int read_sys_metadata_field16(u64 field_id, u16 *val) +static int __read_sys_metadata_field(u64 field_id, void *val, int size) { u64 tmp; int ret; - BUILD_BUG_ON(MD_FIELD_ID_ELE_SIZE_CODE(field_id) != - MD_FIELD_ID_ELE_SIZE_16BIT); - - ret = read_sys_metadata_field(field_id, &tmp); + ret = tdh_sys_rd(field_id, &tmp); if (ret) return ret; - *val = tmp; + memcpy(val, &tmp, size); return 0; } +/* Wrapper to read one global metadata to u8/u16/u32/u64 */ +#define read_sys_metadata_field(_field_id, _val) \ + ({ \ + BUILD_BUG_ON(MD_FIELD_ELE_SIZE(_field_id) != sizeof(typeof(*(_val)))); \ + __read_sys_metadata_field(_field_id, _val, sizeof(typeof(*(_val)))); \ + }) + /* - * Assumes locally defined @ret and @sysinfo_tdmr to convey the error - * code and the 'struct tdx_sys_info_tdmr' instance to fill out. + * Read one global metadata field to a member of a structure instance, + * assuming locally defined @ret to convey the error code. */ -#define TD_SYSINFO_MAP(_field_id, _member) \ - ({ \ - if (!ret) \ - ret = read_sys_metadata_field16(MD_FIELD_ID_##_field_id, \ - &sysinfo_tdmr->_member); \ +#define TD_SYSINFO_MAP(_field_id, _stbuf, _member) \ + ({ \ + if (!ret) \ + ret = read_sys_metadata_field(MD_FIELD_ID_##_field_id, \ + &_stbuf->_member); \ }) static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) { int ret = 0; - TD_SYSINFO_MAP(MAX_TDMRS, max_tdmrs); - TD_SYSINFO_MAP(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr); - TD_SYSINFO_MAP(PAMT_4K_ENTRY_SIZE, pamt_entry_size[TDX_PS_4K]); - TD_SYSINFO_MAP(PAMT_2M_ENTRY_SIZE, pamt_entry_size[TDX_PS_2M]); - TD_SYSINFO_MAP(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]); +#define TD_SYSINFO_MAP_TDMR_INFO(_field_id, _member) \ + TD_SYSINFO_MAP(_field_id, sysinfo_tdmr, _member) + + TD_SYSINFO_MAP_TDMR_INFO(MAX_TDMRS, max_tdmrs); + TD_SYSINFO_MAP_TDMR_INFO(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr); + TD_SYSINFO_MAP_TDMR_INFO(PAMT_4K_ENTRY_SIZE, pamt_entry_size[TDX_PS_4K]); + TD_SYSINFO_MAP_TDMR_INFO(PAMT_2M_ENTRY_SIZE, pamt_entry_size[TDX_PS_2M]); + TD_SYSINFO_MAP_TDMR_INFO(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]); return ret; } diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 148f9b4d1140..7458f6717873 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -53,7 +53,8 @@ #define MD_FIELD_ID_ELE_SIZE_CODE(_field_id) \ (((_field_id) & GENMASK_ULL(33, 32)) >> 32) -#define MD_FIELD_ID_ELE_SIZE_16BIT 1 +#define MD_FIELD_ELE_SIZE(_field_id) \ + (1 << MD_FIELD_ID_ELE_SIZE_CODE(_field_id)) struct tdmr_reserved_area { u64 offset; From patchwork Tue Aug 27 07:14:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778996 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 00259193433; Tue, 27 Aug 2024 07:15:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742903; cv=none; b=m08jSuygO3UwhZvvOBDxFDVYLTxZIbUzDOqzI7PErFUY33J9pMcoKVKE5Jabpzc0SyT3tKeEneUsr8ecHLnFuSso9DTLS/FQt58cYGFe+sAJVgVIcJqJvlZXxBgYh+Q6f+cneC5/h+Gw1qtA69jG3KI8X+OBvHp+/uAu8fA2a/k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742903; c=relaxed/simple; bh=iOwhyk6CLSQyjuOGqBrDGkGAiGKSAVxya3654+z3ijk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jNK1PvAcAplsLqVAJA6GyO8jSQ1OZwUSdtqr/ETkyQ3nGrfKIaV9wB+8rz1DGYBhZJKgPigXkBKaJL4AgsZS/dxsm5P/yYGc8m0/IKQ20TDvty1ieYEUvgVBWF/flnvji+S6YscMFAskGTUf3LqMKOkDBUtyOJlQt9MXV4xwXSY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=kuhvFa7l; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="kuhvFa7l" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742902; x=1756278902; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=iOwhyk6CLSQyjuOGqBrDGkGAiGKSAVxya3654+z3ijk=; b=kuhvFa7leEBch9kkxIn4VcUCOBIua3uaGRpdxqa0YfLWpw/sPuXH/25b bfAfPsTrK0fhJbxihiTLM+cHDZ3QIK9Xk/uatlTpY0y+PrRRODH3DNHWi CY19Hb7YVbyp5G9Zi4F21uJVHRLOmbcmrAnA+0UURF3pAKPzsGlRXe9ay 5WH8xHwSDjNL0TzJb+8D4VFe9kmVv68IJYEPWKgfF1CB7umOAalymnFOe VzMqqWW8MJxBcAOEc738tTVSl9DCW5tC3pnFla7xJKuSxkHRTDYoyfsOs Vu6psqwwUk9WHG8Yu362udrCgcdjAattZ0Su7RG/MnW8fomjQ72jrSWo4 A==; X-CSE-ConnectionGUID: 9fDw87EwRaqPO8va65SsYQ== X-CSE-MsgGUID: +5jcyY/+Tz+nIdKM7sbWaw== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575865" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575865" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:02 -0700 X-CSE-ConnectionGUID: tU0Zo3MbTIiCeJ3bX2bJqA== X-CSE-MsgGUID: kWMwzKxAQkK5DzDJE2Ypng== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092571" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:14:57 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 4/8] x86/virt/tdx: Refine a comment to reflect the latest TDX spec Date: Tue, 27 Aug 2024 19:14:26 +1200 Message-ID: <88b2198138d89a9d5dc89b42efaed9ae669ae1c0.1724741926.git.kai.huang@intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The old versions of "Intel TDX Module v1.5 ABI Specification" contain the definitions of all global metadata field IDs directly in a table. However, the latest spec moves those definitions to a dedicated 'global_metadata.json' file as part of a new (separate) "Intel TDX Module v1.5 ABI definitions" [1]. Update the comment to reflect this. [1]: https://cdrdv2.intel.com/v1/dl/getContent/795381 Reported-by: Nikolay Borisov Signed-off-by: Kai Huang Reviewed-by: Adrian Hunter Reviewed-by: Nikolay Borisov --- arch/x86/virt/vmx/tdx/tdx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 7458f6717873..8aabd03d8bf5 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -29,7 +29,7 @@ /* * Global scope metadata field ID. * - * See Table "Global Scope Metadata", TDX module 1.5 ABI spec. + * See the "global_metadata.json" in the "TDX 1.5 ABI definitions". */ #define MD_FIELD_ID_MAX_TDMRS 0x9100000100000008ULL #define MD_FIELD_ID_MAX_RESERVED_PER_TDMR 0x9100000100000009ULL From patchwork Tue Aug 27 07:14:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778997 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 84D02198837; Tue, 27 Aug 2024 07:15:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742908; cv=none; b=aZiLHAQK1mA3PchHUyB5RvqS80OTa2EiEGXjEGyNXnr332rEZU3FePIuBjpmeIwjGRdVGWB9XMmOVw5RIiFRcb4qxqbMlok82cYzvTkdPTwh/Kq7D2HroCuQUs5FwNiW8HUuvHk8UOEDL2r8ECSMpWOEBJ56e6EQdBMEC6AhPKM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742908; c=relaxed/simple; bh=8j1JpumKRiAlfRGl7WTqXqAxcV9FvwH+JqcwOXUhQgQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=i3W3mYy8YTu4X1trpw1HYVwLvwQhktIpPCm6RASTi0dKMoWBmipMoGfkULW64FotUoT74e84Cyq9NxqKje3MmWHkjNqXFhwaF8idCdG54p5uhLnfjoHIKZdRtvwXbFLntLTZjrKbAr1BFT0DVKATzKmFVxgZ1uGGKUuRaXqN8ys= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=P+QKvUjd; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="P+QKvUjd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742907; x=1756278907; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8j1JpumKRiAlfRGl7WTqXqAxcV9FvwH+JqcwOXUhQgQ=; b=P+QKvUjdD31UPWpqtHSRsAqWFc5K8w4qIbSyITZj4O+LOrnsF2S0ujAi vmpBN1NvfVW9XooK6KTA47E6WCP6rPstkoakNVu4t2s72A26/CG5UmVas DJ0i34shfQwUDvjf9lGdMWFnd1JI1554OgdVYy3X0ByfukWBgT/tkG67O rnQrpdLIrMWUs1/2ZE26BNa52rx39Z+njb6iSw+ZvS+jRI92KyTGxYh/4 czvsDYS/fdnZNCRDDCNBGiL8sKioxm/dH7bIH+Fiq0Wn9WHBfPpiexCpC xWrWgHP6V5r9sPR9b03CrTnOfKU/pgmNMJewV7RanMmpKrD879D+yi8XG g==; X-CSE-ConnectionGUID: N0JnyMAwQ9Kw8Z5uACnCxg== X-CSE-MsgGUID: tiytNBLWRX6U/c1upZXN8Q== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575873" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575873" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:06 -0700 X-CSE-ConnectionGUID: AARzS7DFTjmSzPoaQ6FjEQ== X-CSE-MsgGUID: VHdMYHH4SXOAUV9etSA7QQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092583" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:02 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 5/8] x86/virt/tdx: Start to track all global metadata in one structure Date: Tue, 27 Aug 2024 19:14:27 +1200 Message-ID: <994a0df50534c404d1b243a95067860fc296172a.1724741926.git.kai.huang@intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The TDX module provides a set of "global metadata fields". They report things like TDX module version, supported features, and fields related to create/run TDX guests and so on. Currently the kernel only reads "TD Memory Region" (TDMR) related fields for module initialization. There are immediate needs which require the TDX module initialization to read more global metadata including module version, supported features and "Convertible Memory Regions" (CMRs). Also, KVM will need to read more metadata fields to support baseline TDX guests. In the longer term, other TDX features like TDX Connect (which supports assigning trusted IO devices to TDX guest) may also require other kernel components such as pci/vt-d to access global metadata. To meet all those requirements, the idea is the TDX host core-kernel to to provide a centralized, canonical, and read-only structure for the global metadata that comes out from the TDX module for all kernel components to use. As the first step, introduce a new 'struct tdx_sys_info' to track all global metadata fields. TDX categories global metadata fields into different "Class"es. E.g., the TDMR related fields are under class "TDMR Info". Instead of making 'struct tdx_sys_info' a plain structure to contain all metadata fields, organize them in smaller structures based on the "Class". This allows those metadata fields to be used in finer granularity thus makes the code more clear. E.g., the construct_tdmr() can just take the structure which contains "TDMR Info" metadata fields. Add a new function get_tdx_sys_info() as the placeholder to read all metadata fields, and call it at the beginning of init_tdx_module(). For now it only calls get_tdx_sys_info_tdmr() to read TDMR related fields. Note there is a functional change: get_tdx_sys_info_tdmr() is moved from after build_tdx_memlist() to before it, but it is fine to do so. Signed-off-by: Kai Huang Reviewed-by: Adrian Hunter --- v2 -> v3: - Split out the part to rename 'struct tdx_tdmr_sysinfo' to 'struct tdx_sys_info_tdmr'. --- arch/x86/virt/vmx/tdx/tdx.c | 19 ++++++++++++------- arch/x86/virt/vmx/tdx/tdx.h | 36 +++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 1cd9035c783f..24eb289c80e8 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -318,6 +318,11 @@ static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) return ret; } +static int get_tdx_sys_info(struct tdx_sys_info *sysinfo) +{ + return get_tdx_sys_info_tdmr(&sysinfo->tdmr); +} + /* Calculate the actual TDMR size */ static int tdmr_size_single(u16 max_reserved_per_tdmr) { @@ -1090,9 +1095,13 @@ static int init_tdmrs(struct tdmr_info_list *tdmr_list) static int init_tdx_module(void) { - struct tdx_sys_info_tdmr sysinfo_tdmr; + struct tdx_sys_info sysinfo; int ret; + ret = get_tdx_sys_info(&sysinfo); + if (ret) + return ret; + /* * To keep things simple, assume that all TDX-protected memory * will come from the page allocator. Make sure all pages in the @@ -1109,17 +1118,13 @@ static int init_tdx_module(void) if (ret) goto out_put_tdxmem; - ret = get_tdx_sys_info_tdmr(&sysinfo_tdmr); - if (ret) - goto err_free_tdxmem; - /* Allocate enough space for constructing TDMRs */ - ret = alloc_tdmr_list(&tdx_tdmr_list, &sysinfo_tdmr); + ret = alloc_tdmr_list(&tdx_tdmr_list, &sysinfo.tdmr); if (ret) goto err_free_tdxmem; /* Cover all TDX-usable memory regions in TDMRs */ - ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &sysinfo_tdmr); + ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &sysinfo.tdmr); if (ret) goto err_free_tdmrs; diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 8aabd03d8bf5..4cddbb035b9f 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -100,13 +100,6 @@ struct tdx_memblock { int nid; }; -/* "TDMR info" part of "Global Scope Metadata" for constructing TDMRs */ -struct tdx_sys_info_tdmr { - u16 max_tdmrs; - u16 max_reserved_per_tdmr; - u16 pamt_entry_size[TDX_PS_NR]; -}; - /* Warn if kernel has less than TDMR_NR_WARN TDMRs after allocation */ #define TDMR_NR_WARN 4 @@ -119,4 +112,33 @@ struct tdmr_info_list { int max_tdmrs; /* How many 'tdmr_info's are allocated */ }; +/* + * Kernel-defined structures to contain "Global Scope Metadata". + * + * TDX global metadata fields are categorized by "Class"es. See the + * "global_metadata.json" in the "TDX 1.5 ABI Definitions". + * + * 'struct tdx_sys_info' is the main structure to contain all metadata + * used by the kernel. It contains sub-structures with each reflecting + * the "Class" in the 'global_metadata.json'. + * + * Note the structure name may not exactly follow the name of the + * "Class" in the TDX spec, but the comment of that structure always + * reflect that. + * + * Also note not all metadata fields in each class are defined, only + * those used by the kernel are. + */ + +/* Class "TDMR info" */ +struct tdx_sys_info_tdmr { + u16 max_tdmrs; + u16 max_reserved_per_tdmr; + u16 pamt_entry_size[TDX_PS_NR]; +}; + +struct tdx_sys_info { + struct tdx_sys_info_tdmr tdmr; +}; + #endif From patchwork Tue Aug 27 07:14:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778998 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C963E1946B5; Tue, 27 Aug 2024 07:15:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742912; cv=none; b=CCdCggjrjitFFi6lflVAFiw4Z1PyK2JPkHfxGg/CRqYLcI2GGL3Uzxr9l9FFNhHI1an57d1N0QTf4OJW2Mhyo0WZI3e6ZnkzkQikDrrjyWXJI/0wvJskWQczThS4EMsIUB3Hzpijm3WHeH1qOntmgzGy4xVDrsywn+grCySov9w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742912; c=relaxed/simple; bh=naR7oyrXnYK4ZyaV9GWH6oxGFu/wW9QWZ6ymgdAFMBQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=n3k/9wJzdiG+EbLKM3GmX1M+ryWJHxS5/Lz0amg3JbUsyKFie88NIDiWEkyxWyHf8y1JhnDKkurtqdmq/UkdZfkk/viwOYIEObnBc/+KC9QOpBKJWDsHQto6b8ZvLEAB8GI69H4N3By8slCJE0xzUH/28gW0Ne5tZBbPDyDAb7A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=StrAYr4j; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="StrAYr4j" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742911; x=1756278911; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=naR7oyrXnYK4ZyaV9GWH6oxGFu/wW9QWZ6ymgdAFMBQ=; b=StrAYr4jRJjk1bKYZ3zNWf1i+wJKZ+3yJbgMRSMGtl7+XAtTSprLvwqt YZt4x3IWl26ylmNG/DhhoHgGUK8TjsxaHxuDKu7XOx6c7zd1M6+4gq+qG goB5UrUE6488tVdJeaIrtM/6ugbd5CvEc8Q1WHmNYYvesi4+M7siVPcvY IDMyjv6lV5Jo158AMlLmXWJQr4YYkhecS8WpH652qruCa0Jnuf0rn8YGc 6xHQsRNncEYaf2UgHAiOdIHKr02GQnF79TOLc6TVIXQLarUW9DXMOC3m0 yjhtFbaLqCMMF9MsTmkWvcWkYsnE5mgTpdj5PaBlWWlebm/HuG0shF6z0 A==; X-CSE-ConnectionGUID: KliIB/9FRmaUOmc6XMkF1w== X-CSE-MsgGUID: sagE2R+RTBOrDk0Obn1cng== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575883" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575883" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:11 -0700 X-CSE-ConnectionGUID: OHirEoQzTJCyZy0tjKgG6g== X-CSE-MsgGUID: 99XRxLVQSsaX0OPzQf41hw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092600" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:06 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 6/8] x86/virt/tdx: Print TDX module basic information Date: Tue, 27 Aug 2024 19:14:28 +1200 Message-ID: X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently the kernel doesn't print any information regarding the TDX module itself, e.g. module version. In practice such information is useful, especially to the developers. For instance, there are a couple of use cases for dumping module basic information: 1) When something goes wrong around using TDX, the information like TDX module version, supported features etc could be helpful [1][2]. 2) For Linux, when the user wants to update the TDX module, one needs to replace the old module in a specific location in the EFI partition with the new one so that after reboot the BIOS can load it. However, after kernel boots, currently the user has no way to verify it is indeed the new module that gets loaded and initialized (e.g., error could happen when replacing the old module). With the module version dumped the user can verify this easily. So dump the basic TDX module information: - TDX module version, and the build date. - TDX_FEATURES0: Supported TDX features. And dump the information right after reading global metadata, so that this information is printed no matter whether module initialization fails or not. The actual dmesg will look like: virt/tdx: Initializing TDX module: 1.5.00.00.0481 (build_date 20230323), TDX_FEATURES0 0xfbf Link: https://lore.kernel.org/lkml/e2d844ad-182a-4fc0-a06a-d609c9cbef74@suse.com/T/#m352829aedf6680d4628c7e40dc40b332eda93355 [1] Link: https://lore.kernel.org/lkml/e2d844ad-182a-4fc0-a06a-d609c9cbef74@suse.com/T/#m351ebcbc006d2e5bc3e7650206a087cb2708d451 [2] Signed-off-by: Kai Huang --- v2 -> v3: - 'struct tdx_sysinfo_module_info' -> 'struct tdx_sys_info_features' - 'struct tdx_sysinfo_module_version' -> 'struct tdx_sys_info_version' - Remove the 'sys_attributes' and the check of debug/production module. https://lore.kernel.org/kvm/cover.1721186590.git.kai.huang@intel.com/T/#md73dd9b02a492acf4a6facae63e8d030e320967d --- arch/x86/virt/vmx/tdx/tdx.c | 61 +++++++++++++++++++++++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.h | 34 ++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 24eb289c80e8..0fb673dd43ed 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -302,6 +302,55 @@ static int __read_sys_metadata_field(u64 field_id, void *val, int size) &_stbuf->_member); \ }) +static int get_tdx_sys_info_features(struct tdx_sys_info_features *sysinfo_features) +{ + int ret = 0; + +#define TD_SYSINFO_MAP_MOD_FEATURES(_field_id, _member) \ + TD_SYSINFO_MAP(_field_id, sysinfo_features, _member) + + TD_SYSINFO_MAP_MOD_FEATURES(TDX_FEATURES0, tdx_features0); + + return ret; +} + +static int get_tdx_sys_info_version(struct tdx_sys_info_version *sysinfo_version) +{ + int ret = 0; + +#define TD_SYSINFO_MAP_MOD_VERSION(_field_id, _member) \ + TD_SYSINFO_MAP(_field_id, sysinfo_version, _member) + + TD_SYSINFO_MAP_MOD_VERSION(MAJOR_VERSION, major); + TD_SYSINFO_MAP_MOD_VERSION(MINOR_VERSION, minor); + TD_SYSINFO_MAP_MOD_VERSION(UPDATE_VERSION, update); + TD_SYSINFO_MAP_MOD_VERSION(INTERNAL_VERSION, internal); + TD_SYSINFO_MAP_MOD_VERSION(BUILD_NUM, build_num); + TD_SYSINFO_MAP_MOD_VERSION(BUILD_DATE, build_date); + + return ret; +} + +static void print_basic_sys_info(struct tdx_sys_info *sysinfo) +{ + struct tdx_sys_info_features *features = &sysinfo->features; + struct tdx_sys_info_version *version = &sysinfo->version; + + /* + * TDX module version encoding: + * + * .... + * + * When printed as text, and are 1-digit, + * and are 2-digits and + * is 4-digits. + */ + pr_info("Initializing TDX module: %u.%u.%02u.%02u.%04u (build_date %u), TDX_FEATURES0 0x%llx\n", + version->major, version->minor, version->update, + version->internal, version->build_num, + version->build_date, features->tdx_features0); +} + static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) { int ret = 0; @@ -320,6 +369,16 @@ static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) static int get_tdx_sys_info(struct tdx_sys_info *sysinfo) { + int ret; + + ret = get_tdx_sys_info_features(&sysinfo->features); + if (ret) + return ret; + + ret = get_tdx_sys_info_version(&sysinfo->version); + if (ret) + return ret; + return get_tdx_sys_info_tdmr(&sysinfo->tdmr); } @@ -1102,6 +1161,8 @@ static int init_tdx_module(void) if (ret) return ret; + print_basic_sys_info(&sysinfo); + /* * To keep things simple, assume that all TDX-protected memory * will come from the page allocator. Make sure all pages in the diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 4cddbb035b9f..b422e8517e01 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -31,6 +31,15 @@ * * See the "global_metadata.json" in the "TDX 1.5 ABI definitions". */ +#define MD_FIELD_ID_SYS_ATTRIBUTES 0x0A00000200000000ULL +#define MD_FIELD_ID_TDX_FEATURES0 0x0A00000300000008ULL +#define MD_FIELD_ID_BUILD_DATE 0x8800000200000001ULL +#define MD_FIELD_ID_BUILD_NUM 0x8800000100000002ULL +#define MD_FIELD_ID_MINOR_VERSION 0x0800000100000003ULL +#define MD_FIELD_ID_MAJOR_VERSION 0x0800000100000004ULL +#define MD_FIELD_ID_UPDATE_VERSION 0x0800000100000005ULL +#define MD_FIELD_ID_INTERNAL_VERSION 0x0800000100000006ULL + #define MD_FIELD_ID_MAX_TDMRS 0x9100000100000008ULL #define MD_FIELD_ID_MAX_RESERVED_PER_TDMR 0x9100000100000009ULL #define MD_FIELD_ID_PAMT_4K_ENTRY_SIZE 0x9100000100000010ULL @@ -130,6 +139,27 @@ struct tdmr_info_list { * those used by the kernel are. */ +/* + * Class "TDX Module Info". + * + * This class also contains other fields like SYS_ATTRIBUTES and the + * NUM_TDX_FEATURES. For now only TDX_FEATURES0 is needed, but still + * keep the structure to follow the spec (and for future extension). + */ +struct tdx_sys_info_features { + u64 tdx_features0; +}; + +/* Class "TDX Module Version" */ +struct tdx_sys_info_version { + u16 major; + u16 minor; + u16 update; + u16 internal; + u16 build_num; + u32 build_date; +}; + /* Class "TDMR info" */ struct tdx_sys_info_tdmr { u16 max_tdmrs; @@ -138,7 +168,9 @@ struct tdx_sys_info_tdmr { }; struct tdx_sys_info { - struct tdx_sys_info_tdmr tdmr; + struct tdx_sys_info_features features; + struct tdx_sys_info_version version; + struct tdx_sys_info_tdmr tdmr; }; #endif From patchwork Tue Aug 27 07:14:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13778999 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C455B19AD6E; Tue, 27 Aug 2024 07:15:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742917; cv=none; b=YBVri7SdbIyo39+3nLPpKSi4SAhfJiDZL+HLIpXH7FWS7b5b04jAZL3yhBOa30E0Sf5MpMd+357R5qCDu4TgWvd7Enex5CS4gPxz7k3mSP/CtyOu4BOUP9JvwFcF05w1e/vCgdQCvW+JRhYIbqjmn2DtATU969N9Hfn+3fl5LRA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742917; c=relaxed/simple; bh=RXDc6b4OUzhtwoF89rktWuplovOoRNK3eXbyVTIuvxo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RU+WwqFiHyTPlCSmYGXRQLsleawjAm1duHsmlZvtCuVoyNZQNHj681QnP37UeaqWLbw9dF2cyNBHh9bHHlx3jO8aTD56yK9t1aqUbTrC6aTFMB0YuVbAyM9tWIbnquQLzoPUs99w9AKERGZ4OzMRisZS1P2Y3LNUiG2shhgODI8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=LT/Vycw+; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="LT/Vycw+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742916; x=1756278916; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RXDc6b4OUzhtwoF89rktWuplovOoRNK3eXbyVTIuvxo=; b=LT/Vycw+kSvP5EgxFEHm2iyPLDPfrlD5S3pUfdSwVcZi0QtugkxOwbUz 8klpZGq6e4ZldXvOQ98z104y/dVIXEV5TfqB5nKZKrhDs9q2bPhHEPkd3 9alIPocaWbUlQjrhAEUE4wWU0n4K1QkgyMUdgcoZVKX5pXFYuZmhXfOGd tDVn+4M5GEDB7g12OCn0XkmkKZw+1OpXOocNG3wW/RfDeOcV9J3F3cNHn jMneyTlLyClXr5Kz4iBarMv7+wLiV+AqXOrP27WDSqiAkWt7pPOGX49An QaC2O2bjvxnmjsO3jweO9rVhU05PgKHTQgLPUFzbb4GTFE0EcdSiw/g/+ w==; X-CSE-ConnectionGUID: TbGN4IeCTce7mlyxHA4JwA== X-CSE-MsgGUID: NGndbHZsSEGygblc7c9ATQ== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575893" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575893" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:16 -0700 X-CSE-ConnectionGUID: 80KUF/VGSom5EtY8vp+yEg== X-CSE-MsgGUID: beLaeEagS5mlFWlkAG7O8w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092614" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:11 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 7/8] x86/virt/tdx: Reduce TDMR's reserved areas by using CMRs to find memory holes Date: Tue, 27 Aug 2024 19:14:29 +1200 Message-ID: <9b55398a1537302fb7135330dba54e79bfabffb1.1724741926.git.kai.huang@intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 A TDX module initialization failure was reported on a Emerald Rapids platform: virt/tdx: initialization failed: TDMR [0x0, 0x80000000): reserved areas exhausted. virt/tdx: module initialization failed (-28) As part of initializing the TDX module, the kernel informs the TDX module of all "TDX-usable memory regions" using an array of TDX defined structure "TD Memory Region" (TDMR). Each TDMR must be in 1GB aligned and in 1GB granularity, and all "non-TDX-usable memory holes" within a given TDMR must be marked as "reserved areas". The TDX module reports a maximum number of reserved areas that can be supported per TDMR. Currently, the kernel finds those "non-TDX-usable memory holes" within a given TDMR by walking over a list of "TDX-usable memory regions", which essentially reflects the "usable" regions in the e820 table (w/o memory hotplug operations precisely, but this is not relevant here). As shown above, the root cause of this failure is when the kernel tries to construct a TDMR to cover address range [0x0, 0x80000000), there are too many memory holes within that range and the number of memory holes exceeds the maximum number of reserved areas. The E820 table of that platform (see [1] below) reflects this: the number of memory holes among e820 "usable" entries exceeds 16, which is the maximum number of reserved areas TDX module supports in practice. === Fix === There are two options to fix this: 1) reduce the number of memory holes when constructing a TDMR to save "reserved areas"; 2) reduce the TDMR's size to cover fewer memory regions, thus fewer memory holes. Option 1) is possible, and in fact is easier and preferable: TDX actually has a concept of "Convertible Memory Regions" (CMRs). TDX reports a list of CMRs that meet TDX's security requirements on memory. TDX requires all the "TDX-usable memory regions" that the kernel passes to the module via TDMRs, a.k.a, all the "non-reserved regions in TDMRs", must be convertible memory. In other words, if a memory hole is indeed CMR, then it's not mandatory for the kernel to add it to the reserved areas. By doing so, the number of consumed reserved areas can be reduced w/o having any functional impact. The kernel still allocates TDX memory from the page allocator. There's no harm if the kernel tells the TDX module some memory regions are "TDX-usable" but they will never be allocated by the kernel as TDX memory. Note this doesn't have any security impact either because the kernel is out of TDX's TCB anyway. This is feasible because in practice the CMRs just reflect the nature of whether the RAM can indeed be used by TDX, thus each CMR tends to be a large, uninterrupted range of memory, i.e., unlike the e820 table which contains numerous "ACPI *" entries in the first 2G range. Refer to [2] for CMRs reported on the problematic platform using off-tree TDX code. So for this particular module initialization failure, the memory holes that are within [0x0, 0x80000000) are mostly indeed CMR. By not adding them to the reserved areas, the number of consumed reserved areas for the TDMR [0x0, 0x80000000) can be dramatically reduced. Option 2) is also theoretically feasible, but it is not desired: It requires more complicated logic to handle splitting TDMR into smaller ones, which isn't trivial. There are limitations to splitting TDMR too, thus it may not always work: 1) The smallest TDMR is 1GB, and it cannot be split any further; 2) This also increases the total number of TDMRs, which also has a maximum value limited by the TDX module. So, fix this issue by using option 1): 1) reading out the CMRs from the TDX module global metadata, and 2) changing to find memory holes for a given TDMR based on CMRs, but not based on the list of "TDX-usable memory regions". Also dump the CMRs in dmesg. They are helpful when something goes wrong around "constructing the TDMRs and configuring the TDX module with them". Note there are no existing userspace tools that the user can get CMRs since they can only be read via SEAMCALL (no CPUID, MSR etc). [1] BIOS-E820 table of the problematic platform: BIOS-e820: [mem 0x0000000000000000-0x000000000009efff] usable BIOS-e820: [mem 0x000000000009f000-0x00000000000fffff] reserved BIOS-e820: [mem 0x0000000000100000-0x000000005d168fff] usable BIOS-e820: [mem 0x000000005d169000-0x000000005d22afff] ACPI data BIOS-e820: [mem 0x000000005d22b000-0x000000005d3cefff] usable BIOS-e820: [mem 0x000000005d3cf000-0x000000005d469fff] reserved BIOS-e820: [mem 0x000000005d46a000-0x000000005e5b2fff] usable BIOS-e820: [mem 0x000000005e5b3000-0x000000005e5c2fff] reserved BIOS-e820: [mem 0x000000005e5c3000-0x000000005e5d2fff] usable BIOS-e820: [mem 0x000000005e5d3000-0x000000005e5e4fff] reserved BIOS-e820: [mem 0x000000005e5e5000-0x000000005eb57fff] usable BIOS-e820: [mem 0x000000005eb58000-0x0000000061357fff] ACPI NVS BIOS-e820: [mem 0x0000000061358000-0x000000006172afff] usable BIOS-e820: [mem 0x000000006172b000-0x0000000061794fff] ACPI data BIOS-e820: [mem 0x0000000061795000-0x00000000617fefff] usable BIOS-e820: [mem 0x00000000617ff000-0x0000000061912fff] ACPI data BIOS-e820: [mem 0x0000000061913000-0x0000000061998fff] usable BIOS-e820: [mem 0x0000000061999000-0x00000000619dffff] ACPI data BIOS-e820: [mem 0x00000000619e0000-0x00000000619e1fff] usable BIOS-e820: [mem 0x00000000619e2000-0x00000000619e9fff] reserved BIOS-e820: [mem 0x00000000619ea000-0x0000000061a26fff] usable BIOS-e820: [mem 0x0000000061a27000-0x0000000061baefff] ACPI data BIOS-e820: [mem 0x0000000061baf000-0x00000000623c2fff] usable BIOS-e820: [mem 0x00000000623c3000-0x0000000062471fff] reserved BIOS-e820: [mem 0x0000000062472000-0x0000000062823fff] usable BIOS-e820: [mem 0x0000000062824000-0x0000000063a24fff] reserved BIOS-e820: [mem 0x0000000063a25000-0x0000000063d57fff] usable BIOS-e820: [mem 0x0000000063d58000-0x0000000064157fff] reserved BIOS-e820: [mem 0x0000000064158000-0x0000000064158fff] usable BIOS-e820: [mem 0x0000000064159000-0x0000000064194fff] reserved BIOS-e820: [mem 0x0000000064195000-0x000000006e9cefff] usable BIOS-e820: [mem 0x000000006e9cf000-0x000000006eccefff] reserved BIOS-e820: [mem 0x000000006eccf000-0x000000006f6fefff] ACPI NVS BIOS-e820: [mem 0x000000006f6ff000-0x000000006f7fefff] ACPI data BIOS-e820: [mem 0x000000006f7ff000-0x000000006f7fffff] usable BIOS-e820: [mem 0x000000006f800000-0x000000008fffffff] reserved ...... [2] Convertible Memory Regions of the problematic platform: virt/tdx: CMR: [0x100000, 0x6f800000) virt/tdx: CMR: [0x100000000, 0x107a000000) virt/tdx: CMR: [0x1080000000, 0x207c000000) virt/tdx: CMR: [0x2080000000, 0x307c000000) virt/tdx: CMR: [0x3080000000, 0x407c000000) Fixes: dde3b60d572c9 ("x86/virt/tdx: Designate reserved areas for all TDMRs") Signed-off-by: Kai Huang --- v2 -> v3: - Add the Fixes tag, although this patch depends on previous patches. - CMR_BASE0 -> CMR_BASE(_i), CMR_SIZE0 -> CMR_SIZE(_i) to silence the build-check error. v1 -> v2: - Change to walk over CMRs directly to find out memory holes, instead of walking over TDX memory blocks and explicitly check whether a hole is subregion of CMR. (Chao) - Mention any constant macro definitions in global metadata structures are TDX architectural. (Binbin) - Slightly improve the changelog. --- arch/x86/virt/vmx/tdx/tdx.c | 105 ++++++++++++++++++++++++++++++------ arch/x86/virt/vmx/tdx/tdx.h | 13 +++++ 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 0fb673dd43ed..fa335ab1ae92 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -331,6 +331,72 @@ static int get_tdx_sys_info_version(struct tdx_sys_info_version *sysinfo_version return ret; } +/* Update the @sysinfo_cmr->num_cmrs to trim tail empty CMRs */ +static void trim_empty_tail_cmrs(struct tdx_sys_info_cmr *sysinfo_cmr) +{ + int i; + + for (i = 0; i < sysinfo_cmr->num_cmrs; i++) { + u64 cmr_base = sysinfo_cmr->cmr_base[i]; + u64 cmr_size = sysinfo_cmr->cmr_size[i]; + + if (!cmr_size) { + WARN_ON_ONCE(cmr_base); + break; + } + + /* TDX architecture: CMR must be 4KB aligned */ + WARN_ON_ONCE(!PAGE_ALIGNED(cmr_base) || + !PAGE_ALIGNED(cmr_size)); + } + + sysinfo_cmr->num_cmrs = i; +} + +static int get_tdx_sys_info_cmr(struct tdx_sys_info_cmr *sysinfo_cmr) +{ + int i, ret = 0; + +#define TD_SYSINFO_MAP_CMR_INFO(_field_id, _member) \ + TD_SYSINFO_MAP(_field_id, sysinfo_cmr, _member) + + TD_SYSINFO_MAP_CMR_INFO(NUM_CMRS, num_cmrs); + + if (ret) + return ret; + + for (i = 0; i < sysinfo_cmr->num_cmrs; i++) { + TD_SYSINFO_MAP_CMR_INFO(CMR_BASE(i), cmr_base[i]); + TD_SYSINFO_MAP_CMR_INFO(CMR_SIZE(i), cmr_size[i]); + } + + if (ret) + return ret; + + /* + * The TDX module may just report the maximum number of CMRs that + * TDX architecturally supports as the actual number of CMRs, + * despite the latter is smaller. In this case all the tail + * CMRs will be empty. Trim them away. + */ + trim_empty_tail_cmrs(sysinfo_cmr); + + return 0; +} + +static void print_sys_info_cmr(struct tdx_sys_info_cmr *sysinfo_cmr) +{ + int i; + + for (i = 0; i < sysinfo_cmr->num_cmrs; i++) { + u64 cmr_base = sysinfo_cmr->cmr_base[i]; + u64 cmr_size = sysinfo_cmr->cmr_size[i]; + + pr_info("CMR[%d]: [0x%llx, 0x%llx)\n", i, cmr_base, + cmr_base + cmr_size); + } +} + static void print_basic_sys_info(struct tdx_sys_info *sysinfo) { struct tdx_sys_info_features *features = &sysinfo->features; @@ -349,6 +415,8 @@ static void print_basic_sys_info(struct tdx_sys_info *sysinfo) version->major, version->minor, version->update, version->internal, version->build_num, version->build_date, features->tdx_features0); + + print_sys_info_cmr(&sysinfo->cmr); } static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr) @@ -379,6 +447,10 @@ static int get_tdx_sys_info(struct tdx_sys_info *sysinfo) if (ret) return ret; + ret = get_tdx_sys_info_cmr(&sysinfo->cmr); + if (ret) + return ret; + return get_tdx_sys_info_tdmr(&sysinfo->tdmr); } @@ -803,29 +875,28 @@ static int tdmr_add_rsvd_area(struct tdmr_info *tdmr, int *p_idx, u64 addr, } /* - * Go through @tmb_list to find holes between memory areas. If any of + * Go through all CMRs in @sysinfo_cmr to find memory holes. If any of * those holes fall within @tdmr, set up a TDMR reserved area to cover * the hole. */ -static int tdmr_populate_rsvd_holes(struct list_head *tmb_list, +static int tdmr_populate_rsvd_holes(struct tdx_sys_info_cmr *sysinfo_cmr, struct tdmr_info *tdmr, int *rsvd_idx, u16 max_reserved_per_tdmr) { - struct tdx_memblock *tmb; u64 prev_end; - int ret; + int i, ret; /* * Start looking for reserved blocks at the * beginning of the TDMR. */ prev_end = tdmr->base; - list_for_each_entry(tmb, tmb_list, list) { + for (i = 0; i < sysinfo_cmr->num_cmrs; i++) { u64 start, end; - start = PFN_PHYS(tmb->start_pfn); - end = PFN_PHYS(tmb->end_pfn); + start = sysinfo_cmr->cmr_base[i]; + end = start + sysinfo_cmr->cmr_size[i]; /* Break if this region is after the TDMR */ if (start >= tdmr_end(tdmr)) @@ -926,16 +997,16 @@ static int rsvd_area_cmp_func(const void *a, const void *b) /* * Populate reserved areas for the given @tdmr, including memory holes - * (via @tmb_list) and PAMTs (via @tdmr_list). + * (via @sysinfo_cmr) and PAMTs (via @tdmr_list). */ static int tdmr_populate_rsvd_areas(struct tdmr_info *tdmr, - struct list_head *tmb_list, + struct tdx_sys_info_cmr *sysinfo_cmr, struct tdmr_info_list *tdmr_list, u16 max_reserved_per_tdmr) { int ret, rsvd_idx = 0; - ret = tdmr_populate_rsvd_holes(tmb_list, tdmr, &rsvd_idx, + ret = tdmr_populate_rsvd_holes(sysinfo_cmr, tdmr, &rsvd_idx, max_reserved_per_tdmr); if (ret) return ret; @@ -954,10 +1025,10 @@ static int tdmr_populate_rsvd_areas(struct tdmr_info *tdmr, /* * Populate reserved areas for all TDMRs in @tdmr_list, including memory - * holes (via @tmb_list) and PAMTs. + * holes (via @sysinfo_cmr) and PAMTs. */ static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, - struct list_head *tmb_list, + struct tdx_sys_info_cmr *sysinfo_cmr, u16 max_reserved_per_tdmr) { int i; @@ -966,7 +1037,7 @@ static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, int ret; ret = tdmr_populate_rsvd_areas(tdmr_entry(tdmr_list, i), - tmb_list, tdmr_list, max_reserved_per_tdmr); + sysinfo_cmr, tdmr_list, max_reserved_per_tdmr); if (ret) return ret; } @@ -981,7 +1052,8 @@ static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, */ static int construct_tdmrs(struct list_head *tmb_list, struct tdmr_info_list *tdmr_list, - struct tdx_sys_info_tdmr *sysinfo_tdmr) + struct tdx_sys_info_tdmr *sysinfo_tdmr, + struct tdx_sys_info_cmr *sysinfo_cmr) { int ret; @@ -994,7 +1066,7 @@ static int construct_tdmrs(struct list_head *tmb_list, if (ret) return ret; - ret = tdmrs_populate_rsvd_areas_all(tdmr_list, tmb_list, + ret = tdmrs_populate_rsvd_areas_all(tdmr_list, sysinfo_cmr, sysinfo_tdmr->max_reserved_per_tdmr); if (ret) tdmrs_free_pamt_all(tdmr_list); @@ -1185,7 +1257,8 @@ static int init_tdx_module(void) goto err_free_tdxmem; /* Cover all TDX-usable memory regions in TDMRs */ - ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &sysinfo.tdmr); + ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &sysinfo.tdmr, + &sysinfo.cmr); if (ret) goto err_free_tdmrs; diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index b422e8517e01..e7bed9e717c7 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -40,6 +40,10 @@ #define MD_FIELD_ID_UPDATE_VERSION 0x0800000100000005ULL #define MD_FIELD_ID_INTERNAL_VERSION 0x0800000100000006ULL +#define MD_FIELD_ID_NUM_CMRS 0x9000000100000000ULL +#define MD_FIELD_ID_CMR_BASE(_i) (0x9000000300000080ULL + (u16)_i) +#define MD_FIELD_ID_CMR_SIZE(_i) (0x9000000300000100ULL + (u16)_i) + #define MD_FIELD_ID_MAX_TDMRS 0x9100000100000008ULL #define MD_FIELD_ID_MAX_RESERVED_PER_TDMR 0x9100000100000009ULL #define MD_FIELD_ID_PAMT_4K_ENTRY_SIZE 0x9100000100000010ULL @@ -160,6 +164,14 @@ struct tdx_sys_info_version { u32 build_date; }; +/* Class "CMR Info" */ +#define TDX_MAX_CMRS 32 /* architectural */ +struct tdx_sys_info_cmr { + u16 num_cmrs; + u64 cmr_base[TDX_MAX_CMRS]; + u64 cmr_size[TDX_MAX_CMRS]; +}; + /* Class "TDMR info" */ struct tdx_sys_info_tdmr { u16 max_tdmrs; @@ -170,6 +182,7 @@ struct tdx_sys_info_tdmr { struct tdx_sys_info { struct tdx_sys_info_features features; struct tdx_sys_info_version version; + struct tdx_sys_info_cmr cmr; struct tdx_sys_info_tdmr tdmr; }; From patchwork Tue Aug 27 07:14:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kai Huang X-Patchwork-Id: 13779000 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E14CB15687C; Tue, 27 Aug 2024 07:15:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742921; cv=none; b=iegM1oWZHlDysH2XXz72Dd7F3QJLwY5OQ3Xfly16HQswObIhXQpAvtWpi9+Wa0x25QU3JuVqPwtD2KRrmSIiQQ44F5fsd/jX71QWW7/eME49d9DvcFpFd9ukDb/9YKwZYtCNHZo1QAbpSdd03UDHAJwn0yZRfdmFVVGEKPd18Nw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724742921; c=relaxed/simple; bh=grormjxrxQ/kWgqfapiq6pNWiEMjNqpZCDAi+voZbC4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hmnHZWr7+47JemDb2ma38nMHPMpxdLPas+qLuCAWJ1J3Jw/z+Y8qAQbCZOvloeB64MGDw/YtT/2v+n5LByn2etEWXSeR4vLl0u+S7S33TbYzG0nblSJArbb/f6UKbzhqd4zbbqopEES25M4cfC046nhR3tu98+oGpTq+Lstqb30= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=bVQHjwgj; arc=none smtp.client-ip=198.175.65.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="bVQHjwgj" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1724742920; x=1756278920; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=grormjxrxQ/kWgqfapiq6pNWiEMjNqpZCDAi+voZbC4=; b=bVQHjwgjYNe7N1d/eUdcdKdCxSyp5tg/StknH1AkHfD7z2ObEKNrP7zi PTHK1yQ76QjwaYN4Jvy1Cp5lyHW3KjTDObbYvijrh5bZhlkl5262qQCBM nwY3bKEbB5SaeuAzRN41FUk9e5LRFvXSipmeBLU9OY6hCRWSqh8vu/qaO j3RKOXlC5KkKzedFElr49SnALIUxGXPK7q4YwqEqXGR96xNy8v0JWf+AN dwCbINV5mhP5UvNoPYcsjFviY0Uej4Yi/4PiCCXWeYbxr6yN1f2pIQCrl FTv8Wcf0ftW+AgBUA04X7Z8VsnCKXdBksyWvMEdxg/k0LyAtuyEdqPmT9 g==; X-CSE-ConnectionGUID: tF2mLAAeTDWxembAzSIMug== X-CSE-MsgGUID: 0Nl5E4wsQb2cowXmQ0X28Q== X-IronPort-AV: E=McAfee;i="6700,10204,11176"; a="34575903" X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="34575903" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:20 -0700 X-CSE-ConnectionGUID: j/0yQ4QDTRe6nBXYDMOnvg== X-CSE-MsgGUID: iCLrDHamRC2ausFN7qh3VA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.10,179,1719903600"; d="scan'208";a="63092623" Received: from apaszkie-mobl2.apaszkie-mobl2 (HELO khuang2-desk.gar.corp.intel.com) ([10.124.223.81]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 27 Aug 2024 00:15:16 -0700 From: Kai Huang To: dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tglx@linutronix.de, bp@alien8.de, peterz@infradead.org, mingo@redhat.com, hpa@zytor.com, dan.j.williams@intel.com, seanjc@google.com, pbonzini@redhat.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, rick.p.edgecombe@intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, binbin.wu@linux.intel.com, adrian.hunter@intel.com, kai.huang@intel.com Subject: [PATCH v3 8/8] x86/virt/tdx: Don't initialize module that doesn't support NO_RBP_MOD feature Date: Tue, 27 Aug 2024 19:14:30 +1200 Message-ID: <0996e2f1b3e5c72150708b10bff57ad726c69e4b.1724741926.git.kai.huang@intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Old TDX modules can clobber RBP in the TDH.VP.ENTER SEAMCALL. However RBP is used as frame pointer in the x86_64 calling convention, and clobbering RBP could result in bad things like being unable to unwind the stack if any non-maskable exceptions (NMI, #MC etc) happens in that gap. A new "NO_RBP_MOD" feature was introduced to more recent TDX modules to not clobber RBP. This feature is reported in the TDX_FEATURES0 global metadata field via bit 18. Don't initialize the TDX module if this feature is not supported [1]. Link: https://lore.kernel.org/all/c0067319-2653-4cbd-8fee-1ccf21b1e646@suse.com/T/#mef98469c51e2382ead2c537ea189752360bd2bef [1] Signed-off-by: Kai Huang Reviewed-by: Nikolay Borisov Reviewed-by: Adrian Hunter Reviewed-by: Dan Williams --- v2 -> v3: - check_module_compatibility() -> check_features(). - Improve error message. https://lore.kernel.org/kvm/cover.1721186590.git.kai.huang@intel.com/T/#md9e2eeef927838cbf20d7b361cdbea518b8aec50 --- arch/x86/virt/vmx/tdx/tdx.c | 17 +++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.h | 3 +++ 2 files changed, 20 insertions(+) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index fa335ab1ae92..032a53ddf5bc 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -454,6 +454,18 @@ static int get_tdx_sys_info(struct tdx_sys_info *sysinfo) return get_tdx_sys_info_tdmr(&sysinfo->tdmr); } +static int check_features(struct tdx_sys_info *sysinfo) +{ + u64 tdx_features0 = sysinfo->features.tdx_features0; + + if (!(tdx_features0 & TDX_FEATURES0_NO_RBP_MOD)) { + pr_err("frame pointer (RBP) clobber bug present, upgrade TDX module\n"); + return -EINVAL; + } + + return 0; +} + /* Calculate the actual TDMR size */ static int tdmr_size_single(u16 max_reserved_per_tdmr) { @@ -1235,6 +1247,11 @@ static int init_tdx_module(void) print_basic_sys_info(&sysinfo); + /* Check whether the kernel can support this module */ + ret = check_features(&sysinfo); + if (ret) + return ret; + /* * To keep things simple, assume that all TDX-protected memory * will come from the page allocator. Make sure all pages in the diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index e7bed9e717c7..831361e6d0fb 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -154,6 +154,9 @@ struct tdx_sys_info_features { u64 tdx_features0; }; +/* Architectural bit definitions of TDX_FEATURES0 metadata field */ +#define TDX_FEATURES0_NO_RBP_MOD _BITULL(18) + /* Class "TDX Module Version" */ struct tdx_sys_info_version { u16 major;