From patchwork Mon Nov 21 00:26:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13050218 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 207CFC4332F for ; Mon, 21 Nov 2022 00:28:11 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id BA6896B0095; Sun, 20 Nov 2022 19:28:10 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id B7D746B0096; Sun, 20 Nov 2022 19:28:10 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A45648E0001; Sun, 20 Nov 2022 19:28:10 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 967B16B0095 for ; Sun, 20 Nov 2022 19:28:10 -0500 (EST) Received: from smtpin29.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 75AB81C6036 for ; Mon, 21 Nov 2022 00:28:10 +0000 (UTC) X-FDA: 80155562340.29.58CCFDF Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by imf22.hostedemail.com (Postfix) with ESMTP id D3362C000B for ; Mon, 21 Nov 2022 00:28:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1668990489; x=1700526489; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=jIBcb5cVMwmxp99dDnDGXF9eYbfG3mWlVut9+yUNmLc=; b=VRcySu2LQm0VauNnj2GrbnkDvXFM+aesP31X7WnkeoAqmtRfl9I7DoLO 1drwKHJAk7rI4TAZUw5evgEV3qgqKl794Qgls/X/RMjqeOFv6AgvwsRXg CabUSvorxF4JsSfUmUtKlumvRic17+hzljUpQ4iq7Tq5yqBMe2RWs2IIk N+jJnUGBh6n+FPQNeXRWrw2yG08AGKvgDR/yrSGON/mII/iBv76VXttU4 8HEWmRPIP2O6sSCcfnAlPvYf434volKPc1hUmGt1kgbDCAnfrteGjCSYR fa1sosSTnjDgwpsayJiPt/FhGsCpXZftCyuxqNU1Ql8N3XLtfZ+8i3nyc g==; X-IronPort-AV: E=McAfee;i="6500,9779,10537"; a="296803740" X-IronPort-AV: E=Sophos;i="5.96,180,1665471600"; d="scan'208";a="296803740" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Nov 2022 16:28:09 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10537"; a="729825533" X-IronPort-AV: E=Sophos;i="5.96,180,1665471600"; d="scan'208";a="729825533" Received: from tomnavar-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.176.15]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Nov 2022 16:28:05 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, seanjc@google.com, pbonzini@redhat.com, dave.hansen@intel.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, peterz@infradead.org, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v7 17/20] x86/virt/tdx: Configure global KeyID on all packages Date: Mon, 21 Nov 2022 13:26:39 +1300 Message-Id: <8d8285cc5efa6302cf42a3fe2c9153d1a9dbcdac.1668988357.git.kai.huang@intel.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: References: MIME-Version: 1.0 ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1668990490; a=rsa-sha256; cv=none; b=ImDd27Fl09Wz8qSyb1n8P0QtoJS7ibCRTQWCZMBfCalyNiVuCzeYPqvjerCVBl1pHfqo5a gT5LfyXUK5KXN7lDHw1LsImls/62mknZGw3aE2g24V7FVf4BIVts5TXYh9iiwAtuis786u Zv/Ueqe3AX6AgIBYFxxssiPVlDlKCS4= ARC-Authentication-Results: i=1; imf22.hostedemail.com; dkim=none ("invalid DKIM record") header.d=intel.com header.s=Intel header.b=VRcySu2L; spf=pass (imf22.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.126 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1668990490; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=1ZDrmZlNcxV6f+e5/5Q37GQIdNjaxpt17aZEM/WACYk=; b=tZDNBtI5wBTOb3+DAxgvQzBRuCCw6WYaANNaC/MPLC0pJIjFpcKcSmdHSxmZYAnZm4QvBC fuugzEKn68pHQ5xCae7+XJDKbSA08AbMdh/wa4faELSLMMx2ZYCUcJLp790X2NyOYvhdGN Puph4XSxuEdTAFM610SE0gu2V5FVkek= X-Rspam-User: X-Stat-Signature: cy8otm4mfmcq1myouchjbih8gjuyt1q6 X-Rspamd-Queue-Id: D3362C000B Authentication-Results: imf22.hostedemail.com; dkim=none ("invalid DKIM record") header.d=intel.com header.s=Intel header.b=VRcySu2L; spf=pass (imf22.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.126 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com X-Rspamd-Server: rspam07 X-HE-Tag: 1668990489-836514 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: After the array of TDMRs and the global KeyID are configured to the TDX module, use TDH.SYS.KEY.CONFIG to configure the key of the global KeyID on all packages. TDH.SYS.KEY.CONFIG must be done on one (any) cpu for each package. And it cannot run concurrently on different CPUs. Implement a helper to run SEAMCALL on one cpu for each package one by one, and use it to configure the global KeyID on all packages. Intel hardware doesn't guarantee cache coherency across different KeyIDs. The kernel needs to flush PAMT's dirty cachelines (associated with KeyID 0) before the TDX module uses the global KeyID to access the PAMT. Following the TDX module specification, flush cache before configuring the global KeyID on all packages. Given the PAMT size can be large (~1/256th of system RAM), just use WBINVD on all CPUs to flush. Note if any TDH.SYS.KEY.CONFIG fails, the TDX module may already have used the global KeyID to write any PAMT. Therefore, need to use WBINVD to flush cache before freeing the PAMTs back to the kernel. Note using MOVDIR64B (which changes the page's associated KeyID from the old TDX private KeyID back to KeyID 0, which is used by the kernel) to clear PMATs isn't needed, as the KeyID 0 doesn't support integrity check. Reviewed-by: Isaku Yamahata Signed-off-by: Kai Huang --- v6 -> v7: - Improved changelong and comment to explain why MOVDIR64B isn't used when returning PAMTs back to the kernel. --- arch/x86/virt/vmx/tdx/tdx.c | 89 ++++++++++++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 1 + 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 3a032930e58a..99d1be5941a7 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -224,6 +224,46 @@ static void seamcall_on_each_cpu(struct seamcall_ctx *sc) on_each_cpu(seamcall_smp_call_function, sc, true); } +/* + * Call one SEAMCALL on one (any) cpu for each physical package in + * serialized way. Return immediately in case of any error if + * SEAMCALL fails on any cpu. + * + * Note for serialized calls 'struct seamcall_ctx::err' doesn't have + * to be atomic, but for simplicity just reuse it instead of adding + * a new one. + */ +static int seamcall_on_each_package_serialized(struct seamcall_ctx *sc) +{ + cpumask_var_t packages; + int cpu, ret = 0; + + if (!zalloc_cpumask_var(&packages, GFP_KERNEL)) + return -ENOMEM; + + for_each_online_cpu(cpu) { + if (cpumask_test_and_set_cpu(topology_physical_package_id(cpu), + packages)) + continue; + + ret = smp_call_function_single(cpu, seamcall_smp_call_function, + sc, true); + if (ret) + break; + + /* + * Doesn't have to use atomic_read(), but it doesn't + * hurt either. + */ + ret = atomic_read(&sc->err); + if (ret) + break; + } + + free_cpumask_var(packages); + return ret; +} + static int tdx_module_init_cpus(void) { struct seamcall_ctx sc = { .fn = TDH_SYS_LP_INIT }; @@ -1010,6 +1050,22 @@ static int config_tdx_module(struct tdmr_info *tdmr_array, int tdmr_num, return ret; } +static int config_global_keyid(void) +{ + struct seamcall_ctx sc = { .fn = TDH_SYS_KEY_CONFIG }; + + /* + * Configure the key of the global KeyID on all packages by + * calling TDH.SYS.KEY.CONFIG on all packages in a serialized + * way as it cannot run concurrently on different CPUs. + * + * TDH.SYS.KEY.CONFIG may fail with entropy error (which is + * a recoverable error). Assume this is exceedingly rare and + * just return error if encountered instead of retrying. + */ + return seamcall_on_each_package_serialized(&sc); +} + /* * Detect and initialize the TDX module. * @@ -1098,15 +1154,44 @@ static int init_tdx_module(void) if (ret) goto out_free_pamts; + /* + * Hardware doesn't guarantee cache coherency across different + * KeyIDs. The kernel needs to flush PAMT's dirty cachelines + * (associated with KeyID 0) before the TDX module can use the + * global KeyID to access the PAMT. Given PAMTs are potentially + * large (~1/256th of system RAM), just use WBINVD on all cpus + * to flush the cache. + * + * Follow the TDX spec to flush cache before configuring the + * global KeyID on all packages. + */ + wbinvd_on_all_cpus(); + + /* Config the key of global KeyID on all packages */ + ret = config_global_keyid(); + if (ret) + goto out_free_pamts; + /* * Return -EINVAL until all steps of TDX module initialization * process are done. */ ret = -EINVAL; out_free_pamts: - if (ret) + if (ret) { + /* + * Part of PAMT may already have been initialized by + * TDX module. Flush cache before returning PAMT back + * to the kernel. + * + * Note there's no need to do MOVDIR64B (which changes + * the page's associated KeyID from the old TDX private + * KeyID back to KeyID 0, which is used by the kernel), + * as KeyID 0 doesn't support integrity check. + */ + wbinvd_on_all_cpus(); tdmrs_free_pamt_all(tdmr_array, tdmr_num); - else + } else pr_info("%lu pages allocated for PAMT.\n", tdmrs_count_pamt_pages(tdmr_array, tdmr_num)); out_free_tdmrs: diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index c26bab2555ca..768d097412ab 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -15,6 +15,7 @@ /* * TDX module SEAMCALL leaf functions */ +#define TDH_SYS_KEY_CONFIG 31 #define TDH_SYS_INFO 32 #define TDH_SYS_INIT 33 #define TDH_SYS_LP_INIT 35