From nobody Fri Dec 19 00:36:40 2025 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) (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 1DE48262D2A for ; Mon, 24 Mar 2025 14:21:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=193.142.43.55 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742826093; cv=none; b=As4uKwHps/OR7Ucd6ZmDEVB1PldeLW1zQPgwCJ8Jc1YlCXPxnBQbhRqLNZFt93mnzajrow0JOktJ94oX8JOq2lwpRFhWIw8YHxGxrx0DSO/cjYEPhiJLOaC6PLiLwv5KlkHWuxvdUSE+VbuIwj/yxF0gFY9nZ2kw5P6+y92QE3U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742826093; c=relaxed/simple; bh=CWzDzV9WkeT3NVx3S+77beRZgfgEX6McvtpWsmaoxeE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xwhsg4b/5RALWEYgHpHWbCjV9pHwIlCEd/pAY9f6Dkw7SRdeIKo/LuUxACm5D5IXOgYfRCXCX7gvSKeC/Rq/3A/NdSq3L4AjcMGSU2RDVpBjDD9MNamGfNipkMpqHu8VwagH9xUH5gG1Pda8HTL7CDscNLcDUbzDeIlJv9sFuwY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de; spf=pass smtp.mailfrom=linutronix.de; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=qQok99My; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b=JRnU/E8N; arc=none smtp.client-ip=193.142.43.55 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linutronix.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="qQok99My"; dkim=permerror (0-bit key) header.d=linutronix.de header.i=@linutronix.de header.b="JRnU/E8N" From: "Ahmed S. Darwish" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1742826090; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GKF6tN/roj0XApjiNOmY4sh8uEAK0MbjBL1IP5D5/m4=; b=qQok99MykriWZdslCdH1g3DeJuAi3xobemtUQmXNk/dkeMd0aQ/psISYyiWdAw6AlvOuKJ qO6lqHhKhNX4qoQ5WqFlOECm/eIW/WdpTpWy0hFIttKULZsQOT7Deon2288CDEkfYLX5nz QHm8w4bAjO2Fu7ktH9mDDs5wd9pe5tGBZiGxT2PObbkbwttvfQ1s9C+yFlD70FYStx8w50 Px4MExSe+XBX6LcTgq7UVyuaQs4P8UxGIv8jUnDX7IZz6k1flqaJv8uWu25wg8844yfkzW 4+jPjsGSMYvSabB8AzY745usrfY2iJEn1zqDqzo8UtR1UwJOLsuDRbtjGT38Sg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1742826090; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GKF6tN/roj0XApjiNOmY4sh8uEAK0MbjBL1IP5D5/m4=; b=JRnU/E8Na4TlaWP1RJA3X8Nw222ktncypbKfSPWU0uJcbq1QoZXvvEx769S21/rTVNAynM WQ/l7h/8HZ1nARDQ== To: Ingo Molnar , Borislav Petkov , Dave Hansen Cc: Thomas Gleixner , Andrew Cooper , "H. Peter Anvin" , John Ogness , x86@kernel.org, x86-cpuid@lists.linux.dev, LKML , "Ahmed S. Darwish" Subject: [PATCH v3 14/20] tools/x86/kcpuid: Filter valid CPUID ranges Date: Mon, 24 Mar 2025 15:20:35 +0100 Message-ID: <20250324142042.29010-15-darwi@linutronix.de> In-Reply-To: <20250324142042.29010-1-darwi@linutronix.de> References: <20250324142042.29010-1-darwi@linutronix.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Next commits will introduce vendor-specific CPUID ranges like Transmeta's 0x8086000 range and Centaur's 0xc0000000. Initially explicit vendor detection was implemented, but it turned out to be not strictly necessary. As Dave Hansen noted, even established tools like cpuid(1) just tries all ranges indices, and see if the CPU responds back with something sensible. Do something similar at setup_cpuid_range(). Query the range's index, and check the maximum range function value returned. If it's within an expected interval of [range_index, range_index + MAX_RANGE_INDEX_OFFSET], accept the range as valid and further query its leaves. Set MAX_RANGE_INDEX_OFFSET to a heuristic of 0xff. That should be sensible enough since all the ranges covered by x86-cpuid-db XML database are: 0x00000000 0x00000023 0x40000000 0x40000000 0x80000000 0x80000026 0x80860000 0x80860007 0xc0000000 0xc0000001 At setup_cpuid_range(), if the range's returned maximum function was not sane, mark it as invalid by setting its number of leaves, range->nr, to zero. Introduce the for_each_valid_cpuid_range() iterator instead of sprinkling "range->nr !=3D 0" checks throughout the code. Suggested-by: Dave Hansen Signed-off-by: Ahmed S. Darwish --- tools/arch/x86/kcpuid/kcpuid.c | 37 +++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/tools/arch/x86/kcpuid/kcpuid.c b/tools/arch/x86/kcpuid/kcpuid.c index 8f81fd66e8dd..94a5926d00d0 100644 --- a/tools/arch/x86/kcpuid/kcpuid.c +++ b/tools/arch/x86/kcpuid/kcpuid.c @@ -96,8 +96,13 @@ static char *range_to_str(struct cpuid_range *range) } } =20 -#define for_each_cpuid_range(range) \ - for (unsigned int i =3D 0; i < ARRAY_SIZE(ranges) && ((range) =3D &ranges= [i]); i++) +#define __for_each_cpuid_range(range, __condition) \ + for (unsigned int i =3D 0; \ + i < ARRAY_SIZE(ranges) && ((range) =3D &ranges[i]) && (__condition);= \ + i++) + +#define for_each_valid_cpuid_range(range) __for_each_cpuid_range(range, (r= ange)->nr !=3D 0) +#define for_each_cpuid_range(range) __for_each_cpuid_range(range, true) =20 struct cpuid_range *index_to_cpuid_range(u32 index) { @@ -105,7 +110,7 @@ struct cpuid_range *index_to_cpuid_range(u32 index) u32 range_idx =3D index & CPUID_INDEX_MASK; struct cpuid_range *range; =20 - for_each_cpuid_range(range) { + for_each_valid_cpuid_range(range) { if (range->index =3D=3D range_idx && (u32)range->nr > func_idx) return range; } @@ -223,20 +228,32 @@ static void raw_dump_range(struct cpuid_range *range) } =20 #define MAX_SUBLEAF_NUM 64 +#define MAX_RANGE_INDEX_OFFSET 0xff void setup_cpuid_range(struct cpuid_range *range) { - u32 max_func, idx_func; + u32 max_func, range_funcs_sz; u32 eax, ebx, ecx, edx; =20 cpuid(range->index, max_func, ebx, ecx, edx); =20 - idx_func =3D (max_func & CPUID_FUNCTION_MASK) + 1; - range->funcs =3D malloc(sizeof(struct cpuid_func) * idx_func); + /* + * If the CPUID range's maximum function value is garbage, then it + * is not recognized by this CPU. Set the range's number of valid + * leaves to zero so that for_each_valid_cpu_range() can ignore it. + */ + if (max_func < range->index || max_func > (range->index + MAX_RANGE_INDEX= _OFFSET)) { + range->nr =3D 0; + return; + } + + range->nr =3D (max_func & CPUID_FUNCTION_MASK) + 1; + range_funcs_sz =3D range->nr * sizeof(struct cpuid_func); + + range->funcs =3D malloc(range_funcs_sz); if (!range->funcs) err(EXIT_FAILURE, NULL); =20 - range->nr =3D idx_func; - memset(range->funcs, 0, sizeof(struct cpuid_func) * idx_func); + memset(range->funcs, 0, range_funcs_sz); =20 for (u32 f =3D range->index; f <=3D max_func; f++) { u32 max_subleaf =3D MAX_SUBLEAF_NUM; @@ -523,7 +540,7 @@ static void show_info(void) =20 if (show_raw) { /* Show all of the raw output of 'cpuid' instr */ - for_each_cpuid_range(range) + for_each_valid_cpuid_range(range) raw_dump_range(range); return; } @@ -552,7 +569,7 @@ static void show_info(void) } =20 printf("CPU features:\n=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n\n"); - for_each_cpuid_range(range) + for_each_valid_cpuid_range(range) show_range(range); } =20 --=20 2.48.1