1 /*
2 * Copyright (C) 2014-2021 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * This code is a complete clean re-write of the stress tool by
19 * Colin Ian King <colin.king@canonical.com> and attempts to be
20 * backwardly compatible with the stress tool by Amos Waterland
21 * <apw@rossby.metr.ou.edu> but has more stress tests and more
22 * functionality.
23 *
24 */
25 #include "stress-ng.h"
26 /* Input -> Output */
27 #define CPUID_tsc (1U << 4) /* EAX=0x1 -> EDX */
28 #define CPUID_msr (1U << 5) /* EAX=0x1 -> EDX */
29 #define CPUID_clfsh (1U << 19) /* EAX=0x1 -> EDX */
30 #define CPUID_rdrand (1U << 30) /* EAX=0x1 -> ECX */
31 #define CPUID_rdseed (1U << 18) /* EAX=0x7, ECX=0x0 -> EBX */
32 #define CPUID_pcommit (1U << 22) /* EAX=0x7, ECX=0x0, -> EBX */
33 #define CPUID_clflushopt (1U << 23) /* EAX=0x7, ECX=0x0, -> EBX */
34 #define CPUID_clwb (1U << 24) /* EAX=0x7, ECX=0x0, -> EBX */
35 #define CPUID_cldemote (1U << 25) /* EAX=0x7, ECX=00x, -> ECX */
36 #define CPUID_syscall (1U << 11) /* EAX=0x80000001 -> EDX */
37
38 /*
39 * stress_x86_cpuid()
40 * cpuid for x86
41 */
stress_x86_cpuid(uint32_t * eax,uint32_t * ebx,uint32_t * ecx,uint32_t * edx)42 void stress_x86_cpuid(
43 uint32_t *eax,
44 uint32_t *ebx,
45 uint32_t *ecx,
46 uint32_t *edx)
47 {
48 #if defined(STRESS_ARCH_X86)
49 asm volatile("cpuid"
50 : "=a" (*eax),
51 "=b" (*ebx),
52 "=c" (*ecx),
53 "=d" (*edx)
54 : "0" (*eax), "2" (*ecx)
55 : "memory");
56 #else
57 *eax = 0;
58 *ebx = 0;
59 *ecx = 0;
60 *edx = 0;
61 #endif
62 }
63
64 /*
65 * stress_cpu_is_x86()
66 * Intel x86 test
67 */
stress_cpu_is_x86(void)68 bool stress_cpu_is_x86(void)
69 {
70 #if defined(STRESS_ARCH_X86)
71 uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
72
73 /* Intel CPU? */
74 stress_x86_cpuid(&eax, &ebx, &ecx, &edx);
75 if ((memcmp(&ebx, "Genu", 4) == 0) &&
76 (memcmp(&edx, "ineI", 4) == 0) &&
77 (memcmp(&ecx, "ntel", 4) == 0))
78 return true;
79 else
80 return false;
81 #else
82 return false;
83 #endif
84 }
85
86 #if defined(STRESS_ARCH_X86)
87 /*
88 * stress_cpu_x86_extended_features
89 * cpuid EAX=7, ECX=0: Extended Features
90 */
stress_cpu_x86_extended_features(uint32_t * ebx,uint32_t * ecx,uint32_t * edx)91 static void stress_cpu_x86_extended_features(
92 uint32_t *ebx,
93 uint32_t *ecx,
94 uint32_t *edx)
95 {
96 uint32_t eax = 7;
97
98 stress_x86_cpuid(&eax, ebx, ecx, edx);
99 }
100 #endif
101
stress_cpu_x86_has_clflushopt(void)102 bool stress_cpu_x86_has_clflushopt(void)
103 {
104 #if defined(STRESS_ARCH_X86)
105 uint32_t ebx = 0, ecx = 0, edx = 0;
106
107 if (!stress_cpu_is_x86())
108 return false;
109
110 stress_cpu_x86_extended_features(&ebx, &ecx, &edx);
111
112 return !!(ebx & CPUID_clflushopt);
113 #else
114 return false;
115 #endif
116 }
117
stress_cpu_x86_has_clwb(void)118 bool stress_cpu_x86_has_clwb(void)
119 {
120 #if defined(STRESS_ARCH_X86)
121 uint32_t ebx = 0, ecx = 0, edx = 0;
122
123 if (!stress_cpu_is_x86())
124 return false;
125
126 stress_cpu_x86_extended_features(&ebx, &ecx, &edx);
127
128 return !!(ebx & CPUID_clwb);
129 #else
130 return false;
131 #endif
132 }
133
stress_cpu_x86_has_cldemote(void)134 bool stress_cpu_x86_has_cldemote(void)
135 {
136 #if defined(STRESS_ARCH_X86)
137 uint32_t ebx = 0, ecx = 0, edx = 0;
138
139 if (!stress_cpu_is_x86())
140 return false;
141
142 stress_cpu_x86_extended_features(&ebx, &ecx, &edx);
143
144 return !!(ecx & CPUID_cldemote);
145 #else
146 return false;
147 #endif
148 }
149
stress_cpu_x86_has_rdseed(void)150 bool stress_cpu_x86_has_rdseed(void)
151 {
152 #if defined(STRESS_ARCH_X86)
153 uint32_t ebx = 0, ecx = 0, edx = 0;
154
155 if (!stress_cpu_is_x86())
156 return false;
157
158 stress_cpu_x86_extended_features(&ebx, &ecx, &edx);
159
160 return !!(ebx & CPUID_rdseed);
161 #else
162 return false;
163 #endif
164 }
165
stress_cpu_x86_has_syscall(void)166 bool stress_cpu_x86_has_syscall(void)
167 {
168 #if defined(STRESS_ARCH_X86)
169 uint32_t eax = 0x80000001, ebx = 0, ecx = 0, edx = 0;
170
171 if (!stress_cpu_is_x86())
172 return false;
173
174 stress_x86_cpuid(&eax, &ebx, &ecx, &edx);
175
176 return !!(edx & CPUID_syscall);
177 #else
178 return false;
179 #endif
180 }
181
stress_cpu_x86_has_rdrand(void)182 bool stress_cpu_x86_has_rdrand(void)
183 {
184 #if defined(STRESS_ARCH_X86)
185 uint32_t eax = 0x1, ebx = 0, ecx = 0, edx = 0;
186
187 if (!stress_cpu_is_x86())
188 return false;
189
190 stress_x86_cpuid(&eax, &ebx, &ecx, &edx);
191
192 return !!(ecx & CPUID_rdrand);
193 #else
194 return false;
195 #endif
196 }
197
stress_cpu_x86_has_tsc(void)198 bool stress_cpu_x86_has_tsc(void)
199 {
200 #if defined(STRESS_ARCH_X86)
201 uint32_t eax = 0x1, ebx = 0, ecx = 0, edx = 0;
202
203 if (!stress_cpu_is_x86())
204 return false;
205
206 stress_x86_cpuid(&eax, &ebx, &ecx, &edx);
207
208 return !!(edx & CPUID_tsc);
209 #else
210 return false;
211 #endif
212 }
213
stress_cpu_x86_has_msr(void)214 bool stress_cpu_x86_has_msr(void)
215 {
216 #if defined(STRESS_ARCH_X86)
217 uint32_t eax = 0x1, ebx = 0, ecx = 0, edx = 0;
218
219 if (!stress_cpu_is_x86())
220 return false;
221
222 stress_x86_cpuid(&eax, &ebx, &ecx, &edx);
223
224 return !!(edx & CPUID_msr);
225 #else
226 return false;
227 #endif
228 }
229
stress_cpu_x86_has_clfsh(void)230 bool stress_cpu_x86_has_clfsh(void)
231 {
232 #if defined(STRESS_ARCH_X86)
233 uint32_t eax = 0x1, ebx = 0, ecx = 0, edx = 0;
234
235 if (!stress_cpu_is_x86())
236 return false;
237
238 stress_x86_cpuid(&eax, &ebx, &ecx, &edx);
239
240 return !!(edx & CPUID_clfsh);
241 #else
242 return false;
243 #endif
244 }
245