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 | |
25 | static char *cpu_flags; |
26 | |
27 | /* Search for flags in /proc/cpuinfo and store line |
28 | in cpu_flags. */ |
29 | void |
30 | get_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 | |
56 | int |
57 | check_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 | |
104 | static int |
105 | do_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 | |