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