From nobody Mon Feb 9 13:01:17 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7DDF431C57B for ; Thu, 29 Jan 2026 01:15:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769649358; cv=none; b=pxrnD8pT9gktDclfyELuTRIAsYPpnUT0S4XALiQT//zjwKG16/YY4einmT9Mv0TdQ2uFHx2YadxsWfGTqcPurrau3FBzCPPparC0HryygFEJWyrBL3PDHiHGNjtC4XY22h0mcHAYkU/7+vz80eynRVhXXi7dVPVh17JmQ4Mc0i0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769649358; c=relaxed/simple; bh=oX2MlvAYx4zmch8f356wAzFlhGp0Ab7gNL2eHuy2Vxo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=DeLzWud8A5etIseEhX4OX1crz0uz+W4RZdFzf5vYbysDc3ueRCVMM6wTyV2cpIO1T0pM5M3sdvtZbGFW7uEw1e20zac+XzQyVEi7lPJhA7aGc6frBx0RqHJXwOTHez7+yOsU4V3jb2Ep9Jh8f5f+PPHEoco2K6yswy/PlbUTrGw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=EfcR20IN; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="EfcR20IN" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-35301003062so1067090a91.2 for ; Wed, 28 Jan 2026 17:15:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769649353; x=1770254153; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=oWQPx27FCugyzao24/tqQ+m62u9m5MfQopgQbQNuj2c=; b=EfcR20INHGl6b5V3cdxngj/R6SNDzNA/VG+pBDsMrlYdEawTii/UPokRW5d4SixfgR RusxoZ/K/fZSnkg2LslZrrsqBkFTCXImRRDYKIOYTw71mKFj7+D+pHVWVBfdc2RBi3jO igQzmcO50Mf9GCFDXEl433ICdhpZ5oD8mUztTSAOyhEnABGw4kmbS0Rf7P061uS9zelL /hmcDOkfHBNAUprXoQxZRx9+zHVAYyR4+fvvE2hv6aDEWRJHs5CGXxj/3X1e+VD6CWhQ cs15jjaokaKpOS8LpnM6BUEHCHm+pa7n3pIJyqLx4vNgNOqCQQO1nzX274Ul0ZU25R7+ Kbbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769649353; x=1770254153; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=oWQPx27FCugyzao24/tqQ+m62u9m5MfQopgQbQNuj2c=; b=YShvlj++QAO/zhHy94Dd7GUq8KCy9y0JiQjX5HJvYgPB7rV7h7gHkQ4XPXP2/3YJiN ZuQx04Gz0r4MvFX8tEzN191P7f/Bgqy5oJa9smgnIvq3Xq8bYK833j5wOt2LcNRmHD7z jgoImhrwyn89oOeEwSkHJ4LNebNSJcQaRA3I2QoNI8JdAT1zurJuyTDyzJMTBLjnj/D9 df/mErygtjWT7bz8vP1TCJnWEH+WZd4qScU4vG8MwX9qPZkghVCYIF8sesCoiFcJfmAC pKHMwoIWmltA3tuGxiJOLUxV7O0JEcnL3hM1tal1XELC/uufyfFUvpFYb5PNs3qnawBP GDKA== X-Gm-Message-State: AOJu0YzOA7i3Zkrpzfpw5pSuuJrMOhs/ihKifRe9a96jHmGuVCT6gXmZ mQ+WxTVxN1vrwXkgtKDBzFKGSsCUweRu8cfwqIdyG5Dkaeum9LOcaLm5T2dqnrT64NcCtcmNoh/ Gy9qX2A== X-Received: from pjyd6.prod.google.com ([2002:a17:90a:dfc6:b0:353:8d2b:682]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:5183:b0:352:ccae:fe65 with SMTP id 98e67ed59e1d1-353fecba611mr6392881a91.4.1769649352912; Wed, 28 Jan 2026 17:15:52 -0800 (PST) Reply-To: Sean Christopherson Date: Wed, 28 Jan 2026 17:14:45 -0800 In-Reply-To: <20260129011517.3545883-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260129011517.3545883-1-seanjc@google.com> X-Mailer: git-send-email 2.53.0.rc1.217.geba53bf80e-goog Message-ID: <20260129011517.3545883-14-seanjc@google.com> Subject: [RFC PATCH v5 13/45] x86/virt/tdx: Allocate page bitmap for Dynamic PAMT From: Sean Christopherson To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, Kiryl Shutsemau , Sean Christopherson , Paolo Bonzini Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, kvm@vger.kernel.org, Kai Huang , Rick Edgecombe , Yan Zhao , Vishal Annapurve , Ackerley Tng , Sagi Shahar , Binbin Wu , Xiaoyao Li , Isaku Yamahata Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kirill A. Shutemov The Physical Address Metadata Table (PAMT) holds TDX metadata for physical memory and must be allocated by the kernel during TDX module initialization. The exact size of the required PAMT memory is determined by the TDX module and may vary between TDX module versions. Currently it is approximately 0.4% of the system memory. This is a significant commitment, especially if it is not known upfront whether the machine will run any TDX guests. For normal PAMT, each memory region that the TDX module might use (TDMR) needs three separate PAMT allocations. One for each supported page size (1GB, 2MB, 4KB). At a high level, Dynamic PAMT still has the 1GB and 2MB levels allocated on TDX module initialization, but the 4KB level allocated dynamically at TD runtime. However, in the details, the TDX module still needs some per 4KB page data. The TDX module exposed how many bits per page need to be allocated (currently it is 1). The bits-per-page value can then be used to calculate the size to pass in place of the 4KB allocations in the TDMR, which TDX specs call "PAMT_PAGE_BITMAP". So in effect, Dynamic PAMT just needs a different (smaller) size allocation for the 4KB level part of the allocation. Although it is functionally something different, it is passed in the same way the 4KB page size PAMT allocation is. Begin to implement Dynamic PAMT in the kernel by reading the bits-per-page needed for Dynamic PAMT. Calculate the size needed for the bitmap, and use it instead of the 4KB size determined for normal PAMT, in the case of Dynamic PAMT. In doing so, reduce the static allocations to approximately 0.004%, a 100x improvement. Signed-off-by: Kirill A. Shutemov [Enhanced log] Signed-off-by: Rick Edgecombe Reviewed-by: Binbin Wu Tested-by: Sagi Shahar Signed-off-by: Sean Christopherson --- arch/x86/include/asm/tdx.h | 5 +++++ arch/x86/include/asm/tdx_global_metadata.h | 1 + arch/x86/virt/vmx/tdx/tdx.c | 19 ++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 7 +++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 441a26988d3b..57d5f07e3735 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -130,6 +130,11 @@ int tdx_enable(void); const char *tdx_dump_mce_info(struct mce *m); const struct tdx_sys_info *tdx_get_sysinfo(void); =20 +static inline bool tdx_supports_dynamic_pamt(const struct tdx_sys_info *sy= sinfo) +{ + return false; /* To be enabled when kernel is ready */ +} + int tdx_guest_keyid_alloc(void); u32 tdx_get_nr_guest_keyids(void); void tdx_guest_keyid_free(unsigned int keyid); diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/= asm/tdx_global_metadata.h index 060a2ad744bf..5eb808b23997 100644 --- a/arch/x86/include/asm/tdx_global_metadata.h +++ b/arch/x86/include/asm/tdx_global_metadata.h @@ -15,6 +15,7 @@ struct tdx_sys_info_tdmr { u16 pamt_4k_entry_size; u16 pamt_2m_entry_size; u16 pamt_1g_entry_size; + u8 pamt_page_bitmap_entry_bits; }; =20 struct tdx_sys_info_td_ctrl { diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 0c4c873bff80..517c6759c3ca 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -441,6 +441,18 @@ static int fill_out_tdmrs(struct list_head *tmb_list, return 0; } =20 +static unsigned long tdmr_get_pamt_bitmap_sz(struct tdmr_info *tdmr) +{ + unsigned long pamt_sz, nr_pamt_entries; + int bits_per_entry; + + bits_per_entry =3D tdx_sysinfo.tdmr.pamt_page_bitmap_entry_bits; + nr_pamt_entries =3D tdmr->size >> PAGE_SHIFT; + pamt_sz =3D DIV_ROUND_UP(nr_pamt_entries * bits_per_entry, BITS_PER_BYTE); + + return PAGE_ALIGN(pamt_sz); +} + /* * Calculate PAMT size given a TDMR and a page size. The returned * PAMT size is always aligned up to 4K page boundary. @@ -508,7 +520,12 @@ static int tdmr_set_up_pamt(struct tdmr_info *tdmr, * Calculate the PAMT size for each TDX supported page size * and the total PAMT size. */ - tdmr->pamt_4k_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_4K); + if (tdx_supports_dynamic_pamt(&tdx_sysinfo)) { + /* With Dynamic PAMT, PAMT_4K is replaced with a bitmap */ + tdmr->pamt_4k_size =3D tdmr_get_pamt_bitmap_sz(tdmr); + } else { + tdmr->pamt_4k_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_4K); + } tdmr->pamt_2m_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_2M); tdmr->pamt_1g_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_1G); tdmr_pamt_size =3D tdmr->pamt_4k_size + tdmr->pamt_2m_size + tdmr->pamt_1= g_size; diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vm= x/tdx/tdx_global_metadata.c index 13ad2663488b..00ab0e550636 100644 --- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c +++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c @@ -33,6 +33,13 @@ static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdm= r *sysinfo_tdmr) sysinfo_tdmr->pamt_2m_entry_size =3D val; if (!ret && !(ret =3D read_sys_metadata_field(0x9100000100000012, &val))) sysinfo_tdmr->pamt_1g_entry_size =3D val; + /* + * Don't fail here if tdx_supports_dynamic_pamt() isn't supported. The + * TDX code can fallback to normal PAMT if it's not supported. + */ + if (!ret && tdx_supports_dynamic_pamt(&tdx_sysinfo) && + !(ret =3D read_sys_metadata_field(0x9100000100000013, &val))) + sysinfo_tdmr->pamt_page_bitmap_entry_bits =3D val; =20 return ret; } --=20 2.53.0.rc1.217.geba53bf80e-goog