From patchwork Wed Jan 14 06:39:52 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiamei Xie X-Patchwork-Id: 128033 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id E39D84BA2E2C for ; Wed, 14 Jan 2026 06:46:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E39D84BA2E2C X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailgw1.hygon.cn (unknown [101.204.27.37]) by sourceware.org (Postfix) with ESMTP id C88494BA2E04 for ; Wed, 14 Jan 2026 06:44:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C88494BA2E04 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=hygon.cn Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=hygon.cn ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C88494BA2E04 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=101.204.27.37 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768373088; cv=none; b=WC+2RQkGSljvhY2kDWNr27PIRTlPfwLYDFAbg/GqjW9gdsJ2PmFL0tOLvyqoKWydnpw8sU53Pp1oe11TqVyfUtHNzXfB7LNzybzvb1YuU2D2A/nOFo7wcRfB1rGhWZllsHvTq/SRu2IKDeXNFw56vyj9qK9/YTMQwYlBcJTHPA0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1768373088; c=relaxed/simple; bh=oM6NenqRTf7eBHhM9t5KArEeHEcS6SQSLLos044tvPQ=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=BvCYdLeoOUYvmZgfdvcoN5mcKNNKlEQY5lyOYx2QNV2y3CJRD4RLD7lknj3d8JhiYEfM/szm0vidpaj99qrHhr3M5hft/b6wVfCBLY/e3JhBPP78O0bjTuEMtrcTwGgwatzaW+iFnD/390/YWtM4rdVN9ythxssD47cjyqPx2FA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C88494BA2E04 Received: from maildlp1.hygon.cn (unknown [127.0.0.1]) by mailgw1.hygon.cn (Postfix) with ESMTP id 4drc6h6S4dz30HPM for ; Wed, 14 Jan 2026 14:44:44 +0800 (CST) Received: from maildlp1.hygon.cn (unknown [172.23.18.60]) by mailgw1.hygon.cn (Postfix) with ESMTP id 4drc6d6wHfz30HPD for ; Wed, 14 Jan 2026 14:44:41 +0800 (CST) Received: from cncheex04.Hygon.cn (unknown [172.23.18.114]) by maildlp1.hygon.cn (Postfix) with ESMTPS id DD4CA78A8 for ; Wed, 14 Jan 2026 14:44:36 +0800 (CST) Received: from jianyong.hygon.cn (172.19.20.52) by cncheex04.Hygon.cn (172.23.18.114) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.36; Wed, 14 Jan 2026 14:44:42 +0800 From: Jiamei Xie To: , CC: Subject: [PATCH v1 1/1] x86: Fix for cache computation on Hygon under hypervisors Date: Wed, 14 Jan 2026 14:39:52 +0800 Message-ID: <20260114063952.979528-2-xiejiamei@hygon.cn> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260114063952.979528-1-xiejiamei@hygon.cn> References: <20260114063952.979528-1-xiejiamei@hygon.cn> MIME-Version: 1.0 X-Originating-IP: [172.19.20.52] X-ClientProxiedBy: cncheex05.Hygon.cn (172.23.18.115) To cncheex04.Hygon.cn (172.23.18.114) X-Spam-Status: No, score=-9.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org On Hygon CPUs, glibc currently relies on CPUID leaf 0x8000001D to compute cache parameters. This works correctly on bare-metal systems. However, under some hypervisors (e.g. QEMU with -cpu qemu64), the maximum supported extended CPUID leaf is only 0x8000000A, and CPUID 0x8000001D is not exposed. In this case, cache information computed via 0x8000001D is zeroed out. This patch introduces legacy fallback of cache computation based on CPUID 0x80000005 and 0x80000006, consistent with the AMD implementation, to restore correct cache information under such environments. Signed-off-by: Jiamei Xie --- sysdeps/x86/dl-cacheinfo.h | 203 +++++++++++++++++++++++++++++++++---- 1 file changed, 181 insertions(+), 22 deletions(-) diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h index b6520bddaa..c14f0c5776 100644 --- a/sysdeps/x86/dl-cacheinfo.h +++ b/sysdeps/x86/dl-cacheinfo.h @@ -585,35 +585,194 @@ handle_hygon (int name) unsigned int ebx; unsigned int ecx; unsigned int edx; - unsigned int count = 0x1; + unsigned int max_cpuid = 0; + unsigned int fn = 0; + + /* No level 4 cache (yet). */ + if (name > _SC_LEVEL3_CACHE_LINESIZE) + return 0; - if (name >= _SC_LEVEL3_CACHE_SIZE) - count = 0x3; - else if (name >= _SC_LEVEL2_CACHE_SIZE) - count = 0x2; - else if (name >= _SC_LEVEL1_DCACHE_SIZE) - count = 0x0; + __cpuid (0x80000000, max_cpuid, ebx, ecx, edx); + + if (max_cpuid >= 0x8000001D) + /* Use __cpuid__ '0x8000_001D' to compute cache details. */ + { + unsigned int count = 0x1; - /* Use __cpuid__ '0x8000_001D' to compute cache details. */ - __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx); + if (name >= _SC_LEVEL3_CACHE_SIZE) + count = 0x3; + else if (name >= _SC_LEVEL2_CACHE_SIZE) + count = 0x2; + else if (name >= _SC_LEVEL1_DCACHE_SIZE) + count = 0x0; + + __cpuid_count (0x8000001D, count, eax, ebx, ecx, edx); + + if (ecx != 0) + { + switch (name) + { + case _SC_LEVEL1_ICACHE_ASSOC: + case _SC_LEVEL1_DCACHE_ASSOC: + case _SC_LEVEL2_CACHE_ASSOC: + case _SC_LEVEL3_CACHE_ASSOC: + return ((ebx >> 22) & 0x3ff) + 1; + case _SC_LEVEL1_ICACHE_LINESIZE: + case _SC_LEVEL1_DCACHE_LINESIZE: + case _SC_LEVEL2_CACHE_LINESIZE: + case _SC_LEVEL3_CACHE_LINESIZE: + return (ebx & 0xfff) + 1; + case _SC_LEVEL1_ICACHE_SIZE: + case _SC_LEVEL1_DCACHE_SIZE: + case _SC_LEVEL2_CACHE_SIZE: + case _SC_LEVEL3_CACHE_SIZE: + return (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1); + default: + __builtin_unreachable (); + } + return -1; + } + } + + /* Legacy cache computation for some hypervisors that + accidentally configure __cpuid__ '0x8000_001D' to Zero. */ + + fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE); + + if (max_cpuid < fn) + return 0; + + __cpuid (fn, eax, ebx, ecx, edx); + + if (name < _SC_LEVEL1_DCACHE_SIZE) + { + name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE; + ecx = edx; + } switch (name) { - case _SC_LEVEL1_ICACHE_ASSOC: - case _SC_LEVEL1_DCACHE_ASSOC: - case _SC_LEVEL2_CACHE_ASSOC: + case _SC_LEVEL1_DCACHE_SIZE: + return (ecx >> 14) & 0x3fc00; + + case _SC_LEVEL1_DCACHE_ASSOC: + ecx >>= 16; + if ((ecx & 0xff) == 0xff) + { + /* Fully associative. */ + return (ecx << 2) & 0x3fc00; + } + return ecx & 0xff; + + case _SC_LEVEL1_DCACHE_LINESIZE: + return ecx & 0xff; + + case _SC_LEVEL2_CACHE_SIZE: + return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00; + + case _SC_LEVEL2_CACHE_ASSOC: + switch ((ecx >> 12) & 0xf) + { + case 0: + case 1: + case 2: + case 4: + return (ecx >> 12) & 0xf; + case 6: + return 8; + case 8: + return 16; + case 10: + return 32; + case 11: + return 48; + case 12: + return 64; + case 13: + return 96; + case 14: + return 128; + case 15: + return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff); + default: + return 0; + } + + case _SC_LEVEL2_CACHE_LINESIZE: + return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff; + + case _SC_LEVEL3_CACHE_SIZE: + { + long int total_l3_cache = 0, l3_cache_per_thread = 0; + unsigned int threads = 0; + + if ((edx & 0xf000) == 0) + return 0; + + total_l3_cache = (edx & 0x3ffc0000) << 1; + + /* Figure out the number of logical threads that share L3. */ + if (max_cpuid >= 0x80000008) + { + /* Get width of APIC ID. */ + __cpuid (0x80000008, eax, ebx, ecx, edx); + threads = (ecx & 0xff) + 1; + } + + if (threads == 0) + { + /* If APIC ID width is not available, use logical + processor count. */ + __cpuid (0x00000001, eax, ebx, ecx, edx); + if ((edx & (1 << 28)) != 0) + threads = (ebx >> 16) & 0xff; + } + + /* Cap usage of highest cache level to the number of + supported threads. */ + if (threads > 0) + l3_cache_per_thread = total_l3_cache/threads; + + /* Get shared cache per ccx. */ + long int l3_cache_per_ccx = 0; + /* Get number of threads share the L3 cache in CCX. */ + __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); + unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; + l3_cache_per_ccx = l3_cache_per_thread * threads_per_ccx; + return l3_cache_per_ccx; + } + case _SC_LEVEL3_CACHE_ASSOC: - return ((ebx >> 22) & 0x3ff) + 1; - case _SC_LEVEL1_ICACHE_LINESIZE: - case _SC_LEVEL1_DCACHE_LINESIZE: - case _SC_LEVEL2_CACHE_LINESIZE: + switch ((edx >> 12) & 0xf) + { + case 0: + case 1: + case 2: + case 4: + return (edx >> 12) & 0xf; + case 6: + return 8; + case 8: + return 16; + case 10: + return 32; + case 11: + return 48; + case 12: + return 64; + case 13: + return 96; + case 14: + return 128; + case 15: + return ((edx & 0x3ffc0000) << 1) / (edx & 0xff); + default: + return 0; + } + case _SC_LEVEL3_CACHE_LINESIZE: - return (ebx & 0xfff) + 1; - case _SC_LEVEL1_ICACHE_SIZE: - case _SC_LEVEL1_DCACHE_SIZE: - case _SC_LEVEL2_CACHE_SIZE: - case _SC_LEVEL3_CACHE_SIZE: - return (((ebx >> 22) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1); + return (edx & 0xf000) == 0 ? 0 : edx & 0xff; + default: __builtin_unreachable (); }