1/* Test CPU feature data against /proc/cpuinfo.
2 This file is part of the GNU C Library.
3 Copyright (C) 2012-2024 Free Software Foundation, Inc.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <cpu-features.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <stdbool.h>
24
25static char *cpu_flags;
26
27/* Search for flags in /proc/cpuinfo and store line
28 in cpu_flags. */
29void
30get_cpuinfo (void)
31{
32 FILE *f;
33 char *line = NULL;
34 size_t len = 0;
35 ssize_t read;
36
37 f = fopen ("/proc/cpuinfo", "r");
38 if (f == NULL)
39 {
40 printf (format: "cannot open /proc/cpuinfo\n");
41 exit (1);
42 }
43
44 while ((read = getline (lineptr: &line, n: &len, stream: f)) != -1)
45 {
46 if (strncmp (line, "flags", 5) == 0)
47 {
48 cpu_flags = strdup (s: line);
49 break;
50 }
51 }
52 fclose (f);
53 free (ptr: line);
54}
55
56int
57check_proc (const char *proc_name, const char *search_name, int flag,
58 int active, const char *name)
59{
60 int found = 0;
61
62 printf (format: "Checking %s:\n", name);
63 printf (format: " %s: %d\n", name, flag);
64 char *str = strstr (cpu_flags, search_name);
65 if (str == NULL)
66 {
67 /* If searching for " XXX " failed, try " XXX\n". */
68 size_t len = strlen (search_name);
69 char buffer[80];
70 if (len >= sizeof buffer)
71 abort ();
72 memcpy (buffer, search_name, len + 1);
73 buffer[len - 1] = '\n';
74 str = strstr (cpu_flags, buffer);
75 }
76 if (str != NULL)
77 found = 1;
78 printf (format: " cpuinfo (%s): %d\n", proc_name, found);
79
80 if (found != flag)
81 {
82 if (found || active)
83 printf (format: " *** failure ***\n");
84 else
85 {
86 printf (format: " *** missing in /proc/cpuinfo ***\n");
87 return 0;
88 }
89 }
90
91 return (found != flag);
92}
93
94#define CHECK_PROC(str, name) \
95 check_proc (#str, " "#str" ", HAS_CPU_FEATURE (name), \
96 CPU_FEATURE_USABLE (name), \
97 "HAS_CPU_FEATURE (" #name ")")
98
99#define CHECK_PROC_ACTIVE(str, name) \
100 check_proc (#str, " "#str" ", CPU_FEATURE_USABLE (name), \
101 CPU_FEATURE_USABLE (name), \
102 "CPU_FEATURE_USABLE (" #name ")")
103
104static int
105do_test (int argc, char **argv)
106{
107 int fails = 0;
108 const struct cpu_features *cpu_features = __get_cpu_features ();
109
110 get_cpuinfo ();
111 fails += CHECK_PROC (acpi, ACPI);
112 fails += CHECK_PROC (adx, ADX);
113 fails += CHECK_PROC (apic, APIC);
114 fails += CHECK_PROC (aes, AES);
115 fails += CHECK_PROC (amx_bf16, AMX_BF16);
116 fails += CHECK_PROC (amx_int8, AMX_INT8);
117 fails += CHECK_PROC (amx_tile, AMX_TILE);
118 fails += CHECK_PROC (arch_capabilities, ARCH_CAPABILITIES);
119 fails += CHECK_PROC (avx, AVX);
120 fails += CHECK_PROC (avx2, AVX2);
121 fails += CHECK_PROC (avx512_4fmaps, AVX512_4FMAPS);
122 fails += CHECK_PROC (avx512_4vnniw, AVX512_4VNNIW);
123 fails += CHECK_PROC (avx512_bf16, AVX512_BF16);
124 fails += CHECK_PROC (avx512_bitalg, AVX512_BITALG);
125 fails += CHECK_PROC (avx512ifma, AVX512_IFMA);
126 fails += CHECK_PROC (avx512vbmi, AVX512_VBMI);
127 fails += CHECK_PROC (avx512_vbmi2, AVX512_VBMI2);
128 fails += CHECK_PROC (avx512_vnni, AVX512_VNNI);
129 fails += CHECK_PROC (avx512_vp2intersect, AVX512_VP2INTERSECT);
130 fails += CHECK_PROC (avx512_vpopcntdq, AVX512_VPOPCNTDQ);
131 fails += CHECK_PROC (avx512bw, AVX512BW);
132 fails += CHECK_PROC (avx512cd, AVX512CD);
133 fails += CHECK_PROC (avx512er, AVX512ER);
134 fails += CHECK_PROC (avx512dq, AVX512DQ);
135 fails += CHECK_PROC (avx512f, AVX512F);
136 fails += CHECK_PROC (avx512pf, AVX512PF);
137 fails += CHECK_PROC (avx512vl, AVX512VL);
138 fails += CHECK_PROC (bmi1, BMI1);
139 fails += CHECK_PROC (bmi2, BMI2);
140 fails += CHECK_PROC (cldemote, CLDEMOTE);
141 fails += CHECK_PROC (clflushopt, CLFLUSHOPT);
142 fails += CHECK_PROC (clflush, CLFSH);
143 fails += CHECK_PROC (clwb, CLWB);
144 fails += CHECK_PROC (cmov, CMOV);
145 fails += CHECK_PROC (cx16, CMPXCHG16B);
146 fails += CHECK_PROC (cnxt_id, CNXT_ID);
147 fails += CHECK_PROC (core_capabilities, CORE_CAPABILITIES);
148 fails += CHECK_PROC (cx8, CX8);
149 fails += CHECK_PROC (dca, DCA);
150 fails += CHECK_PROC (de, DE);
151 fails += CHECK_PROC (zero_fcs_fds, DEPR_FPU_CS_DS);
152 fails += CHECK_PROC (dts, DS);
153 fails += CHECK_PROC (ds_cpl, DS_CPL);
154 fails += CHECK_PROC (dtes64, DTES64);
155 fails += CHECK_PROC (est, EIST);
156 fails += CHECK_PROC (enqcmd, ENQCMD);
157 fails += CHECK_PROC (erms, ERMS);
158 fails += CHECK_PROC (f16c, F16C);
159 fails += CHECK_PROC (fma, FMA);
160 fails += CHECK_PROC (fma4, FMA4);
161 fails += CHECK_PROC (fpu, FPU);
162 fails += CHECK_PROC (fsgsbase, FSGSBASE);
163 fails += CHECK_PROC (fsrm, FSRM);
164 fails += CHECK_PROC (fxsr, FXSR);
165 fails += CHECK_PROC (gfni, GFNI);
166 fails += CHECK_PROC (hle, HLE);
167 fails += CHECK_PROC (ht, HTT);
168 fails += CHECK_PROC (hybrid, HYBRID);
169 if (cpu_features->basic.kind == arch_kind_intel)
170 {
171 fails += CHECK_PROC (ibrs, IBRS_IBPB);
172 fails += CHECK_PROC (stibp, STIBP);
173 }
174 else if (cpu_features->basic.kind == arch_kind_amd)
175 {
176 fails += CHECK_PROC (ibpb, AMD_IBPB);
177
178 /* The IBRS feature on AMD processors is reported using the Intel feature
179 * on KVM guests (synthetic bit). In both cases the cpuinfo entry is the
180 * same. */
181 if (HAS_CPU_FEATURE (IBRS_IBPB))
182 fails += CHECK_PROC (ibrs, IBRS_IBPB);
183 else
184 fails += CHECK_PROC (ibrs, AMD_IBRS);
185 fails += CHECK_PROC (stibp, AMD_STIBP);
186 }
187 fails += CHECK_PROC (ibt, IBT);
188 fails += CHECK_PROC (invariant_tsc, INVARIANT_TSC);
189 fails += CHECK_PROC (invpcid, INVPCID);
190 fails += CHECK_PROC (flush_l1d, L1D_FLUSH);
191 fails += CHECK_PROC (lahf_lm, LAHF64_SAHF64);
192 fails += CHECK_PROC (lm, LM);
193 fails += CHECK_PROC (lwp, LWP);
194 fails += CHECK_PROC (abm, LZCNT);
195 fails += CHECK_PROC (mca, MCA);
196 fails += CHECK_PROC (mce, MCE);
197 fails += CHECK_PROC (md_clear, MD_CLEAR);
198 fails += CHECK_PROC (mmx, MMX);
199 fails += CHECK_PROC (monitor, MONITOR);
200 fails += CHECK_PROC (movbe, MOVBE);
201 fails += CHECK_PROC (movdiri, MOVDIRI);
202 fails += CHECK_PROC (movdir64b, MOVDIR64B);
203 fails += CHECK_PROC (mpx, MPX);
204 fails += CHECK_PROC (msr, MSR);
205 fails += CHECK_PROC (mtrr, MTRR);
206 fails += CHECK_PROC (nx, NX);
207 fails += CHECK_PROC (ospke, OSPKE);
208#if 0
209 /* NB: /proc/cpuinfo doesn't report this feature. */
210 fails += CHECK_PROC (osxsave, OSXSAVE);
211#endif
212 fails += CHECK_PROC (pae, PAE);
213 fails += CHECK_PROC (pdpe1gb, PAGE1GB);
214 fails += CHECK_PROC (pat, PAT);
215 fails += CHECK_PROC (pbe, PBE);
216 fails += CHECK_PROC (pcid, PCID);
217 fails += CHECK_PROC (pclmulqdq, PCLMULQDQ);
218 fails += CHECK_PROC (pconfig, PCONFIG);
219 fails += CHECK_PROC (pdcm, PDCM);
220 fails += CHECK_PROC (pge, PGE);
221 fails += CHECK_PROC (pks, PKS);
222 fails += CHECK_PROC (pku, PKU);
223 fails += CHECK_PROC (popcnt, POPCNT);
224 fails += CHECK_PROC (3dnowprefetch, PREFETCHW);
225#if 0
226 /* NB: /proc/cpuinfo doesn't report this feature. */
227 fails += CHECK_PROC (prefetchwt1, PREFETCHWT1);
228#endif
229#if 0
230 /* NB: /proc/cpuinfo doesn't report this feature. */
231 fails += CHECK_PROC (ptwrite, PTWRITE);
232#endif
233 fails += CHECK_PROC (pse, PSE);
234 fails += CHECK_PROC (pse36, PSE_36);
235 fails += CHECK_PROC (psn, PSN);
236 fails += CHECK_PROC (rdpid, RDPID);
237 fails += CHECK_PROC (rdrand, RDRAND);
238 fails += CHECK_PROC (rdseed, RDSEED);
239 fails += CHECK_PROC (rdt_a, RDT_A);
240 fails += CHECK_PROC (cqm, RDT_M);
241 fails += CHECK_PROC (rdtscp, RDTSCP);
242 fails += CHECK_PROC (rtm, RTM);
243 fails += CHECK_PROC (sdbg, SDBG);
244 fails += CHECK_PROC (sep, SEP);
245 fails += CHECK_PROC (serialize, SERIALIZE);
246 fails += CHECK_PROC (sgx, SGX);
247 fails += CHECK_PROC (sgx_lc, SGX_LC);
248 fails += CHECK_PROC (sha_ni, SHA);
249 fails += CHECK_PROC (user_shstk, SHSTK);
250 fails += CHECK_PROC (smap, SMAP);
251 fails += CHECK_PROC (smep, SMEP);
252 fails += CHECK_PROC (smx, SMX);
253 fails += CHECK_PROC (ss, SS);
254 if (cpu_features->basic.kind == arch_kind_intel)
255 fails += CHECK_PROC (ssbd, SSBD);
256 else if (cpu_features->basic.kind == arch_kind_amd)
257 {
258 /* This feature is implemented in 2 different ways on AMD processors:
259 newer systems provides AMD_SSBD (function 8000_0008, EBX[24]),
260 while older system proviseds AMD_VIRT_SSBD (function 8000_008,
261 EBX[25]). However for AMD_VIRT_SSBD, kernel shows both 'ssbd'
262 and 'virt_ssbd' on /proc/cpuinfo; while for AMD_SSBD only 'ssbd'
263 is provided. */
264 if (HAS_CPU_FEATURE (AMD_SSBD))
265 fails += CHECK_PROC (ssbd, AMD_SSBD);
266 else if (HAS_CPU_FEATURE (AMD_VIRT_SSBD))
267 fails += CHECK_PROC (virt_ssbd, AMD_VIRT_SSBD);
268 }
269 fails += CHECK_PROC (sse, SSE);
270 fails += CHECK_PROC (sse2, SSE2);
271 fails += CHECK_PROC (pni, SSE3);
272 fails += CHECK_PROC (sse4_1, SSE4_1);
273 fails += CHECK_PROC (sse4_2, SSE4_2);
274 fails += CHECK_PROC (sse4a, SSE4A);
275 fails += CHECK_PROC (ssse3, SSSE3);
276 fails += CHECK_PROC (svm, SVM);
277#ifdef __x86_64__
278 /* NB: SYSCALL_SYSRET is 64-bit only. */
279 fails += CHECK_PROC (syscall, SYSCALL_SYSRET);
280#endif
281 fails += CHECK_PROC (tbm, TBM);
282 fails += CHECK_PROC (tm, TM);
283 fails += CHECK_PROC (tm2, TM2);
284 fails += CHECK_PROC (intel_pt, TRACE);
285 fails += CHECK_PROC (tsc, TSC);
286 fails += CHECK_PROC (tsc_adjust, TSC_ADJUST);
287 fails += CHECK_PROC (tsc_deadline_timer, TSC_DEADLINE);
288 fails += CHECK_PROC (tsxldtrk, TSXLDTRK);
289 fails += CHECK_PROC (umip, UMIP);
290 fails += CHECK_PROC (vaes, VAES);
291 fails += CHECK_PROC (vme, VME);
292 fails += CHECK_PROC (vmx, VMX);
293 fails += CHECK_PROC (vpclmulqdq, VPCLMULQDQ);
294 fails += CHECK_PROC (waitpkg, WAITPKG);
295 fails += CHECK_PROC (wbnoinvd, WBNOINVD);
296 fails += CHECK_PROC (x2apic, X2APIC);
297 fails += CHECK_PROC (xfd, XFD);
298 fails += CHECK_PROC (xgetbv1, XGETBV_ECX_1);
299 fails += CHECK_PROC (xop, XOP);
300 fails += CHECK_PROC (xsave, XSAVE);
301 fails += CHECK_PROC (xsavec, XSAVEC);
302 fails += CHECK_PROC (xsaveopt, XSAVEOPT);
303 fails += CHECK_PROC (xsaves, XSAVES);
304 fails += CHECK_PROC (xtpr, XTPRUPDCTRL);
305
306 fails += CHECK_PROC_ACTIVE (fsgsbase, FSGSBASE);
307
308 printf (format: "%d differences between /proc/cpuinfo and glibc code.\n", fails);
309
310 return (fails != 0);
311}
312
313#include "../../../test-skeleton.c"
314

source code of glibc/sysdeps/x86/tst-cpu-features-cpuinfo.c