From patchwork Mon Jun 26 14:12:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13292982 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 BE797EB64DA for ; Mon, 26 Jun 2023 14:15:07 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5DE108D0007; Mon, 26 Jun 2023 10:15:07 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 562DB8D0001; Mon, 26 Jun 2023 10:15:07 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3DC9A8D0007; Mon, 26 Jun 2023 10:15:07 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 27B908D0001 for ; Mon, 26 Jun 2023 10:15:07 -0400 (EDT) Received: from smtpin08.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id A778B40764 for ; Mon, 26 Jun 2023 14:15:06 +0000 (UTC) X-FDA: 80945095812.08.7D6B9A3 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by imf14.hostedemail.com (Postfix) with ESMTP id 4DFED100014 for ; Mon, 26 Jun 2023 14:15:02 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=P02JZC+t; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.126 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1687788903; 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=DvV91YiyDYgozk+TrGsbWsYyKgYA4Im9XtnK/ndv2DA=; b=ERQny2c/37/11TkE0uuPB6zV6cRHn2UqMGrpzSkcKStD9mKniMuZTpXjbHfLR5N1ghkFiG FePQMtkA1pYooEPgfCyG6lXpuIzR/bOIMQqITHo/dWLppWoDLoXE1kXShVsojE0lOCZOBX yHuK7SI3lebR3m9I5mXlF1WCZACLEV8= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=P02JZC+t; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.126 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1687788903; a=rsa-sha256; cv=none; b=Mjjoac1b4uH4z6eNCQJF+HUH3tsmAgf5tb7LBgkG6r26SV4bTYsOgdYen0AZ8thaU398eT h42pHn04NFVWI3Hm6zbv/idq5FeRAg1gJezILEGVdPl4BoEtQAh7gquCwS1UY4X3aI9N3x npxJqqx0921AvsqnHSHjjtZ8S4ph1tw= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1687788903; x=1719324903; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8oV4KREwo5PEDhmXx7KbXfkbLGkGBGLVGetPY+xR228=; b=P02JZC+tHbXSEjbE3K6knFtteoFMihnLdkA2zlYRADvABHgejTEduinQ D+hkMwcgyvaqszi9L45WOjC4H1Xtkdw1bKlYnSw6vbZvnjWxAbSPwsv6z nqeMgKNTIojkgsocYsbQM8rK2s0+dkc7j5+PevKGaHzGqbxY/hrIuPyzC yT1FnN6bB/YMmyV0x7kChk1yoRKPVVmSx8Zkwn6d2Rjmp6y9wR6Nb1yPm +P3L4s0vz0YkN7KXcXdBf/Xi0FgSExBYiUMl32PRsDEv9KkX7wB3lSqVv YJn0sXOz4vrECBrTLHmDcrImrTB8xKjbWWlNrZDXKvsoRvIrIw9YLnDD8 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10753"; a="346033902" X-IronPort-AV: E=Sophos;i="6.01,159,1684825200"; d="scan'208";a="346033902" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Jun 2023 07:15:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10753"; a="890292378" X-IronPort-AV: E=Sophos;i="6.01,159,1684825200"; d="scan'208";a="890292378" Received: from smithau-mobl1.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.213.179.223]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Jun 2023 07:14:55 -0700 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, x86@kernel.org, dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tony.luck@intel.com, peterz@infradead.org, tglx@linutronix.de, bp@alien8.de, mingo@redhat.com, hpa@zytor.com, seanjc@google.com, pbonzini@redhat.com, david@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, ashok.raj@intel.com, reinette.chatre@intel.com, len.brown@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, ying.huang@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, nik.borisov@suse.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v12 13/22] x86/virt/tdx: Designate reserved areas for all TDMRs Date: Tue, 27 Jun 2023 02:12:43 +1200 Message-Id: <932971243b1b842a59d3fb2b6506823bd732db18.1687784645.git.kai.huang@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 4DFED100014 X-Rspam-User: X-Rspamd-Server: rspam02 X-Stat-Signature: 15ap53349e5s9cyut1xm6sk33wohtxei X-HE-Tag: 1687788902-161937 X-HE-Meta: U2FsdGVkX1+0wdOF6mKFYLXIpfHzsvcuZZUrcKQCSHrkCH40zqstxtjKo4pR8aC2abhXipR5S8cpA6jzTqN+liBVBTHQOkimP6GCvCGNV61edTkycp+euaK1JAO664ocA+oURqW6ZuI2MaUM5I7aJGAqP1pmIndXLkPfByj6y7/rUI3wUoZGSTYFHhr2Kgp77s9/7pNuLWqF5b27T6IvxTBXhpUTWqlI2XrCOEQwCjENhVp1JhE3kds7I814DGpQSC4klv9jYLq5357vAFPZnLq+8pYEHky67gf0u5q8S3mvEKbREbUiGtqzrO6BwdQ+gLFqUFPm/WGgIlrwvLKk1RQ12LLZ0u5UFdkhRHqtCEK4nYNBoA6BHjA2S36nVUNZQTLo5wj0dIa8NzNHQzWzriDE+G52obeTxJZeA15Ydssi7rvIsycx7i1VCqAoi5j+lbty1snpvcqoqtM7abifvKRXFhJ1nJGraV6Ij3hvdi3XjvxzpqBD5h7hHY7qz2rzD8wMb4gUXEl/3scpQwD2t9auFDuaqe/yy0LPN2IgMNkOZZTv/Ln+6xzoN/XoLYltzJ3KI9tEMQLFYU4DiI+JGEfSlKdSXqz+zP9zxSZZWNblJKQElWaaincOmcmLdiJZvDoYKUeoA8ijC0UqFCnEI6VVft1fCe+0Vxxn0hykOxjVjsLL6PXZ3r8FJ8o9MkChrZhAZO9UOo2T5DsSJdwr+3+LkOSmXiZFanH44Fx1bUSKH83PSXKdMC1OIL/drYAw191JRK3Dn9eeG2A191If9lgFISujgImPmAQhJqbdG2AQwdR2vPO1EMJP3ilBtVLTtaeinP8o+iAvxY3O8+RMtlKuEFeYeKe15wnQp8CqPyryVKZ0x5495weoVHE2N6hEx83P4Xmcjzv6j3/UKQdo+Rw6ANUGF+Q1nqgOQl9fJRYxtv98ySMgRcLjk5jeIRUYvYUAHVop2lK6EVX7RY5 Gi3V0in9 2FSt7wVFGE0MaL9ZI7pCFQ7+ANG4jfWRp57BbcYyUudN/pjDgfGysUTmGKczCTfb2ZXy3Os8HnNA6Q9l0hp1A2eHt/txVd6hxxL1XOojrsKOESKd3nmayWMZdcEXS8vmszkEUmfi6GX8ONaFRe0940fliFI6e0cbmkunf 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: As the last step of constructing TDMRs, populate reserved areas for all TDMRs. For each TDMR, put all memory holes within this TDMR to the reserved areas. And for all PAMTs which overlap with this TDMR, put all the overlapping parts to reserved areas too. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata Reviewed-by: Kirill A. Shutemov Reviewed-by: Yuan Yao --- v11 -> v12: - Code change due to tdmr_get_pamt() change from returning pfn/npages to base/size - Added Kirill's tag v10 -> v11: - No update v9 -> v10: - No change. v8 -> v9: - Added comment around 'tdmr_add_rsvd_area()' to point out it doesn't do optimization to save reserved areas. (Dave). v7 -> v8: (Dave) - "set_up" -> "populate" in function name change (Dave). - Improved comment suggested by Dave. - Other changes due to 'struct tdmr_info_list'. v6 -> v7: - No change. v5 -> v6: - Rebase due to using 'tdx_memblock' instead of memblock. - Split tdmr_set_up_rsvd_areas() into two functions to handle memory hole and PAMT respectively. - Added Isaku's Reviewed-by. --- arch/x86/virt/vmx/tdx/tdx.c | 217 ++++++++++++++++++++++++++++++++++-- 1 file changed, 209 insertions(+), 8 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index fd5417577f26..2bcace5cb25c 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -634,6 +635,207 @@ static unsigned long tdmrs_count_pamt_kb(struct tdmr_info_list *tdmr_list) return pamt_size / 1024; } +static int tdmr_add_rsvd_area(struct tdmr_info *tdmr, int *p_idx, u64 addr, + u64 size, u16 max_reserved_per_tdmr) +{ + struct tdmr_reserved_area *rsvd_areas = tdmr->reserved_areas; + int idx = *p_idx; + + /* Reserved area must be 4K aligned in offset and size */ + if (WARN_ON(addr & ~PAGE_MASK || size & ~PAGE_MASK)) + return -EINVAL; + + if (idx >= max_reserved_per_tdmr) { + pr_warn("initialization failed: TDMR [0x%llx, 0x%llx): reserved areas exhausted.\n", + tdmr->base, tdmr_end(tdmr)); + return -ENOSPC; + } + + /* + * Consume one reserved area per call. Make no effort to + * optimize or reduce the number of reserved areas which are + * consumed by contiguous reserved areas, for instance. + */ + rsvd_areas[idx].offset = addr - tdmr->base; + rsvd_areas[idx].size = size; + + *p_idx = idx + 1; + + return 0; +} + +/* + * Go through @tmb_list to find holes between memory areas. 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, + struct tdmr_info *tdmr, + int *rsvd_idx, + u16 max_reserved_per_tdmr) +{ + struct tdx_memblock *tmb; + u64 prev_end; + int ret; + + /* + * Start looking for reserved blocks at the + * beginning of the TDMR. + */ + prev_end = tdmr->base; + list_for_each_entry(tmb, tmb_list, list) { + u64 start, end; + + start = PFN_PHYS(tmb->start_pfn); + end = PFN_PHYS(tmb->end_pfn); + + /* Break if this region is after the TDMR */ + if (start >= tdmr_end(tdmr)) + break; + + /* Exclude regions before this TDMR */ + if (end < tdmr->base) + continue; + + /* + * Skip over memory areas that + * have already been dealt with. + */ + if (start <= prev_end) { + prev_end = end; + continue; + } + + /* Add the hole before this region */ + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end, + start - prev_end, + max_reserved_per_tdmr); + if (ret) + return ret; + + prev_end = end; + } + + /* Add the hole after the last region if it exists. */ + if (prev_end < tdmr_end(tdmr)) { + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end, + tdmr_end(tdmr) - prev_end, + max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* + * Go through @tdmr_list to find all PAMTs. If any of those PAMTs + * overlaps with @tdmr, set up a TDMR reserved area to cover the + * overlapping part. + */ +static int tdmr_populate_rsvd_pamts(struct tdmr_info_list *tdmr_list, + struct tdmr_info *tdmr, + int *rsvd_idx, + u16 max_reserved_per_tdmr) +{ + int i, ret; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + struct tdmr_info *tmp = tdmr_entry(tdmr_list, i); + unsigned long pamt_base, pamt_size, pamt_end; + + tdmr_get_pamt(tmp, &pamt_base, &pamt_size); + /* Each TDMR must already have PAMT allocated */ + WARN_ON_ONCE(!pamt_size|| !pamt_base); + + pamt_end = pamt_base + pamt_size; + /* Skip PAMTs outside of the given TDMR */ + if ((pamt_end <= tdmr->base) || + (pamt_base >= tdmr_end(tdmr))) + continue; + + /* Only mark the part within the TDMR as reserved */ + if (pamt_base < tdmr->base) + pamt_base = tdmr->base; + if (pamt_end > tdmr_end(tdmr)) + pamt_end = tdmr_end(tdmr); + + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, pamt_base, + pamt_end - pamt_base, + max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* Compare function called by sort() for TDMR reserved areas */ +static int rsvd_area_cmp_func(const void *a, const void *b) +{ + struct tdmr_reserved_area *r1 = (struct tdmr_reserved_area *)a; + struct tdmr_reserved_area *r2 = (struct tdmr_reserved_area *)b; + + if (r1->offset + r1->size <= r2->offset) + return -1; + if (r1->offset >= r2->offset + r2->size) + return 1; + + /* Reserved areas cannot overlap. The caller must guarantee. */ + WARN_ON_ONCE(1); + return -1; +} + +/* + * Populate reserved areas for the given @tdmr, including memory holes + * (via @tmb_list) and PAMTs (via @tdmr_list). + */ +static int tdmr_populate_rsvd_areas(struct tdmr_info *tdmr, + struct list_head *tmb_list, + 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, + max_reserved_per_tdmr); + if (ret) + return ret; + + ret = tdmr_populate_rsvd_pamts(tdmr_list, tdmr, &rsvd_idx, + max_reserved_per_tdmr); + if (ret) + return ret; + + /* TDX requires reserved areas listed in address ascending order */ + sort(tdmr->reserved_areas, rsvd_idx, sizeof(struct tdmr_reserved_area), + rsvd_area_cmp_func, NULL); + + return 0; +} + +/* + * Populate reserved areas for all TDMRs in @tdmr_list, including memory + * holes (via @tmb_list) and PAMTs. + */ +static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, + struct list_head *tmb_list, + u16 max_reserved_per_tdmr) +{ + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + int ret; + + ret = tdmr_populate_rsvd_areas(tdmr_entry(tdmr_list, i), + tmb_list, tdmr_list, max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + /* * 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 @@ -653,14 +855,13 @@ static int construct_tdmrs(struct list_head *tmb_list, sysinfo->pamt_entry_size); if (ret) return ret; - /* - * TODO: - * - * - Designate reserved areas for each TDMR. - * - * Return -EINVAL until constructing TDMRs is done - */ - return -EINVAL; + + ret = tdmrs_populate_rsvd_areas_all(tdmr_list, tmb_list, + sysinfo->max_reserved_per_tdmr); + if (ret) + tdmrs_free_pamt_all(tdmr_list); + + return ret; } static int init_tdx_module(void)