comparison cpudetect.c @ 32335:fdf3f93c2828

Move some code around to avoid forward declarations in top-level .c files.
author diego
date Fri, 01 Oct 2010 18:29:35 +0000
parents f3aed7bffcbb
children 5e3f013bf4c2
comparison
equal deleted inserted replaced
32334:541a774ce8e4 32335:fdf3f93c2828
52 * team for SSE support detection and more cpu detect code. 52 * team for SSE support detection and more cpu detect code.
53 */ 53 */
54 54
55 /* I believe this code works. However, it has only been used on a PII and PIII */ 55 /* I believe this code works. However, it has only been used on a PII and PIII */
56 56
57 static void check_os_katmai_support( void );
58
59 // return TRUE if cpuid supported
60 static int has_cpuid(void)
61 {
62 // code from libavcodec:
63 #if ARCH_X86_64
64 return 1;
65 #else
66 long a, c;
67 __asm__ volatile (
68 /* See if CPUID instruction is supported ... */
69 /* ... Get copies of EFLAGS into eax and ecx */
70 "pushfl\n\t"
71 "pop %0\n\t"
72 "mov %0, %1\n\t"
73
74 /* ... Toggle the ID bit in one copy and store */
75 /* to the EFLAGS reg */
76 "xor $0x200000, %0\n\t"
77 "push %0\n\t"
78 "popfl\n\t"
79
80 /* ... Get the (hopefully modified) EFLAGS */
81 "pushfl\n\t"
82 "pop %0\n\t"
83 : "=a" (a), "=c" (c)
84 :
85 : "cc"
86 );
87
88 return a != c;
89 #endif
90 }
91
92 void
93 do_cpuid(unsigned int ax, unsigned int *p)
94 {
95 // code from libavcodec:
96 __asm__ volatile
97 ("mov %%"REG_b", %%"REG_S"\n\t"
98 "cpuid\n\t"
99 "xchg %%"REG_b", %%"REG_S
100 : "=a" (p[0]), "=S" (p[1]),
101 "=c" (p[2]), "=d" (p[3])
102 : "0" (ax));
103 }
104
105 void GetCpuCaps( CpuCaps *caps)
106 {
107 unsigned int regs[4];
108 unsigned int regs2[4];
109
110 memset(caps, 0, sizeof(*caps));
111 caps->isX86=1;
112 caps->cl_size=32; /* default */
113 if (!has_cpuid()) {
114 mp_msg(MSGT_CPUDETECT,MSGL_WARN,"CPUID not supported!??? (maybe an old 486?)\n");
115 return;
116 }
117 do_cpuid(0x00000000, regs); // get _max_ cpuid level and vendor name
118 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU vendor name: %.4s%.4s%.4s max cpuid level: %d\n",
119 (char*) (regs+1),(char*) (regs+3),(char*) (regs+2), regs[0]);
120 if (regs[0]>=0x00000001)
121 {
122 char *tmpstr, *ptmpstr;
123 unsigned cl_size;
124
125 do_cpuid(0x00000001, regs2);
126
127 caps->cpuType=(regs2[0] >> 8)&0xf;
128 caps->cpuModel=(regs2[0] >> 4)&0xf;
129
130 // see AMD64 Architecture Programmer's Manual, Volume 3: General-purpose and
131 // System Instructions, Table 3-2: Effective family computation, page 120.
132 if(caps->cpuType==0xf){
133 // use extended family (P4, IA64, K8)
134 caps->cpuType=0xf+((regs2[0]>>20)&255);
135 }
136 if(caps->cpuType==0xf || caps->cpuType==6)
137 caps->cpuModel |= ((regs2[0]>>16)&0xf) << 4;
138
139 caps->cpuStepping=regs2[0] & 0xf;
140
141 // general feature flags:
142 caps->hasTSC = (regs2[3] & (1 << 8 )) >> 8; // 0x0000010
143 caps->hasMMX = (regs2[3] & (1 << 23 )) >> 23; // 0x0800000
144 caps->hasSSE = (regs2[3] & (1 << 25 )) >> 25; // 0x2000000
145 caps->hasSSE2 = (regs2[3] & (1 << 26 )) >> 26; // 0x4000000
146 caps->hasSSE3 = (regs2[2] & 1); // 0x0000001
147 caps->hasSSSE3 = (regs2[2] & (1 << 9 )) >> 9; // 0x0000200
148 caps->hasMMX2 = caps->hasSSE; // SSE cpus supports mmxext too
149 cl_size = ((regs2[1] >> 8) & 0xFF)*8;
150 if(cl_size) caps->cl_size = cl_size;
151
152 ptmpstr=tmpstr=GetCpuFriendlyName(regs, regs2);
153 while(*ptmpstr == ' ') // strip leading spaces
154 ptmpstr++;
155 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: %s ", ptmpstr);
156 free(tmpstr);
157 mp_msg(MSGT_CPUDETECT,MSGL_V,"(Family: %d, Model: %d, Stepping: %d)\n",
158 caps->cpuType, caps->cpuModel, caps->cpuStepping);
159
160 }
161 do_cpuid(0x80000000, regs);
162 if (regs[0]>=0x80000001) {
163 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cpuid-level: %d\n",regs[0]&0x7FFFFFFF);
164 do_cpuid(0x80000001, regs2);
165 caps->hasMMX |= (regs2[3] & (1 << 23 )) >> 23; // 0x0800000
166 caps->hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22; // 0x400000
167 caps->has3DNow = (regs2[3] & (1 << 31 )) >> 31; //0x80000000
168 caps->has3DNowExt = (regs2[3] & (1 << 30 )) >> 30;
169 caps->hasSSE4a = (regs2[2] & (1 << 6 )) >> 6; // 0x0000040
170 }
171 if(regs[0]>=0x80000006)
172 {
173 do_cpuid(0x80000006, regs2);
174 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cache-info: %d\n",regs2[2]&0x7FFFFFFF);
175 caps->cl_size = regs2[2] & 0xFF;
176 }
177 mp_msg(MSGT_CPUDETECT,MSGL_V,"Detected cache-line size is %u bytes\n",caps->cl_size);
178 #if 0
179 mp_msg(MSGT_CPUDETECT,MSGL_INFO,"cpudetect: MMX=%d MMX2=%d SSE=%d SSE2=%d 3DNow=%d 3DNowExt=%d\n",
180 gCpuCaps.hasMMX,
181 gCpuCaps.hasMMX2,
182 gCpuCaps.hasSSE,
183 gCpuCaps.hasSSE2,
184 gCpuCaps.has3DNow,
185 gCpuCaps.has3DNowExt);
186 #endif
187
188 /* FIXME: Does SSE2 need more OS support, too? */
189 if (caps->hasSSE)
190 check_os_katmai_support();
191 if (!caps->hasSSE)
192 caps->hasSSE2 = 0;
193 // caps->has3DNow=1;
194 // caps->hasMMX2 = 0;
195 // caps->hasMMX = 0;
196
197 #if !CONFIG_RUNTIME_CPUDETECT
198 #if !HAVE_MMX
199 if(caps->hasMMX) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX supported but disabled\n");
200 caps->hasMMX=0;
201 #endif
202 #if !HAVE_MMX2
203 if(caps->hasMMX2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX2 supported but disabled\n");
204 caps->hasMMX2=0;
205 #endif
206 #if !HAVE_SSE
207 if(caps->hasSSE) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE supported but disabled\n");
208 caps->hasSSE=0;
209 #endif
210 #if !HAVE_SSE2
211 if(caps->hasSSE2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE2 supported but disabled\n");
212 caps->hasSSE2=0;
213 #endif
214 #if !HAVE_AMD3DNOW
215 if(caps->has3DNow) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNow supported but disabled\n");
216 caps->has3DNow=0;
217 #endif
218 #if !HAVE_AMD3DNOWEXT
219 if(caps->has3DNowExt) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNowExt supported but disabled\n");
220 caps->has3DNowExt=0;
221 #endif
222 #endif // CONFIG_RUNTIME_CPUDETECT
223 }
224
225 char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]){
226 char vendor[13];
227 char *retname;
228 int i;
229
230 if (NULL==(retname=malloc(256))) {
231 mp_msg(MSGT_CPUDETECT,MSGL_FATAL,"Error: GetCpuFriendlyName() not enough memory\n");
232 exit(1);
233 }
234 retname[0] = '\0';
235
236 sprintf(vendor,"%.4s%.4s%.4s",(char*)(regs+1),(char*)(regs+3),(char*)(regs+2));
237
238 do_cpuid(0x80000000,regs);
239 if (regs[0] >= 0x80000004)
240 {
241 // CPU has built-in namestring
242 for (i = 0x80000002; i <= 0x80000004; i++)
243 {
244 do_cpuid(i, regs);
245 strncat(retname, (char*)regs, 16);
246 }
247 }
248 return retname;
249 }
250
251 #if defined(__linux__) && defined(_POSIX_SOURCE) && !ARCH_X86_64 57 #if defined(__linux__) && defined(_POSIX_SOURCE) && !ARCH_X86_64
252 static void sigill_handler_sse( int signal, struct sigcontext sc ) 58 static void sigill_handler_sse( int signal, struct sigcontext sc )
253 { 59 {
254 mp_msg(MSGT_CPUDETECT,MSGL_V, "SIGILL, " ); 60 mp_msg(MSGT_CPUDETECT,MSGL_V, "SIGILL, " );
255 61
413 */ 219 */
414 mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, leaving disabled.\n" ); 220 mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, leaving disabled.\n" );
415 gCpuCaps.hasSSE=0; 221 gCpuCaps.hasSSE=0;
416 #endif /* __linux__ */ 222 #endif /* __linux__ */
417 } 223 }
224
225
226 // return TRUE if cpuid supported
227 static int has_cpuid(void)
228 {
229 // code from libavcodec:
230 #if ARCH_X86_64
231 return 1;
232 #else
233 long a, c;
234 __asm__ volatile (
235 /* See if CPUID instruction is supported ... */
236 /* ... Get copies of EFLAGS into eax and ecx */
237 "pushfl\n\t"
238 "pop %0\n\t"
239 "mov %0, %1\n\t"
240
241 /* ... Toggle the ID bit in one copy and store */
242 /* to the EFLAGS reg */
243 "xor $0x200000, %0\n\t"
244 "push %0\n\t"
245 "popfl\n\t"
246
247 /* ... Get the (hopefully modified) EFLAGS */
248 "pushfl\n\t"
249 "pop %0\n\t"
250 : "=a" (a), "=c" (c)
251 :
252 : "cc"
253 );
254
255 return a != c;
256 #endif
257 }
258
259 void
260 do_cpuid(unsigned int ax, unsigned int *p)
261 {
262 // code from libavcodec:
263 __asm__ volatile
264 ("mov %%"REG_b", %%"REG_S"\n\t"
265 "cpuid\n\t"
266 "xchg %%"REG_b", %%"REG_S
267 : "=a" (p[0]), "=S" (p[1]),
268 "=c" (p[2]), "=d" (p[3])
269 : "0" (ax));
270 }
271
272 void GetCpuCaps( CpuCaps *caps)
273 {
274 unsigned int regs[4];
275 unsigned int regs2[4];
276
277 memset(caps, 0, sizeof(*caps));
278 caps->isX86=1;
279 caps->cl_size=32; /* default */
280 if (!has_cpuid()) {
281 mp_msg(MSGT_CPUDETECT,MSGL_WARN,"CPUID not supported!??? (maybe an old 486?)\n");
282 return;
283 }
284 do_cpuid(0x00000000, regs); // get _max_ cpuid level and vendor name
285 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU vendor name: %.4s%.4s%.4s max cpuid level: %d\n",
286 (char*) (regs+1),(char*) (regs+3),(char*) (regs+2), regs[0]);
287 if (regs[0]>=0x00000001)
288 {
289 char *tmpstr, *ptmpstr;
290 unsigned cl_size;
291
292 do_cpuid(0x00000001, regs2);
293
294 caps->cpuType=(regs2[0] >> 8)&0xf;
295 caps->cpuModel=(regs2[0] >> 4)&0xf;
296
297 // see AMD64 Architecture Programmer's Manual, Volume 3: General-purpose and
298 // System Instructions, Table 3-2: Effective family computation, page 120.
299 if(caps->cpuType==0xf){
300 // use extended family (P4, IA64, K8)
301 caps->cpuType=0xf+((regs2[0]>>20)&255);
302 }
303 if(caps->cpuType==0xf || caps->cpuType==6)
304 caps->cpuModel |= ((regs2[0]>>16)&0xf) << 4;
305
306 caps->cpuStepping=regs2[0] & 0xf;
307
308 // general feature flags:
309 caps->hasTSC = (regs2[3] & (1 << 8 )) >> 8; // 0x0000010
310 caps->hasMMX = (regs2[3] & (1 << 23 )) >> 23; // 0x0800000
311 caps->hasSSE = (regs2[3] & (1 << 25 )) >> 25; // 0x2000000
312 caps->hasSSE2 = (regs2[3] & (1 << 26 )) >> 26; // 0x4000000
313 caps->hasSSE3 = (regs2[2] & 1); // 0x0000001
314 caps->hasSSSE3 = (regs2[2] & (1 << 9 )) >> 9; // 0x0000200
315 caps->hasMMX2 = caps->hasSSE; // SSE cpus supports mmxext too
316 cl_size = ((regs2[1] >> 8) & 0xFF)*8;
317 if(cl_size) caps->cl_size = cl_size;
318
319 ptmpstr=tmpstr=GetCpuFriendlyName(regs, regs2);
320 while(*ptmpstr == ' ') // strip leading spaces
321 ptmpstr++;
322 mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: %s ", ptmpstr);
323 free(tmpstr);
324 mp_msg(MSGT_CPUDETECT,MSGL_V,"(Family: %d, Model: %d, Stepping: %d)\n",
325 caps->cpuType, caps->cpuModel, caps->cpuStepping);
326
327 }
328 do_cpuid(0x80000000, regs);
329 if (regs[0]>=0x80000001) {
330 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cpuid-level: %d\n",regs[0]&0x7FFFFFFF);
331 do_cpuid(0x80000001, regs2);
332 caps->hasMMX |= (regs2[3] & (1 << 23 )) >> 23; // 0x0800000
333 caps->hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22; // 0x400000
334 caps->has3DNow = (regs2[3] & (1 << 31 )) >> 31; //0x80000000
335 caps->has3DNowExt = (regs2[3] & (1 << 30 )) >> 30;
336 caps->hasSSE4a = (regs2[2] & (1 << 6 )) >> 6; // 0x0000040
337 }
338 if(regs[0]>=0x80000006)
339 {
340 do_cpuid(0x80000006, regs2);
341 mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cache-info: %d\n",regs2[2]&0x7FFFFFFF);
342 caps->cl_size = regs2[2] & 0xFF;
343 }
344 mp_msg(MSGT_CPUDETECT,MSGL_V,"Detected cache-line size is %u bytes\n",caps->cl_size);
345 #if 0
346 mp_msg(MSGT_CPUDETECT,MSGL_INFO,"cpudetect: MMX=%d MMX2=%d SSE=%d SSE2=%d 3DNow=%d 3DNowExt=%d\n",
347 gCpuCaps.hasMMX,
348 gCpuCaps.hasMMX2,
349 gCpuCaps.hasSSE,
350 gCpuCaps.hasSSE2,
351 gCpuCaps.has3DNow,
352 gCpuCaps.has3DNowExt);
353 #endif
354
355 /* FIXME: Does SSE2 need more OS support, too? */
356 if (caps->hasSSE)
357 check_os_katmai_support();
358 if (!caps->hasSSE)
359 caps->hasSSE2 = 0;
360 // caps->has3DNow=1;
361 // caps->hasMMX2 = 0;
362 // caps->hasMMX = 0;
363
364 #if !CONFIG_RUNTIME_CPUDETECT
365 #if !HAVE_MMX
366 if(caps->hasMMX) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX supported but disabled\n");
367 caps->hasMMX=0;
368 #endif
369 #if !HAVE_MMX2
370 if(caps->hasMMX2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX2 supported but disabled\n");
371 caps->hasMMX2=0;
372 #endif
373 #if !HAVE_SSE
374 if(caps->hasSSE) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE supported but disabled\n");
375 caps->hasSSE=0;
376 #endif
377 #if !HAVE_SSE2
378 if(caps->hasSSE2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE2 supported but disabled\n");
379 caps->hasSSE2=0;
380 #endif
381 #if !HAVE_AMD3DNOW
382 if(caps->has3DNow) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNow supported but disabled\n");
383 caps->has3DNow=0;
384 #endif
385 #if !HAVE_AMD3DNOWEXT
386 if(caps->has3DNowExt) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNowExt supported but disabled\n");
387 caps->has3DNowExt=0;
388 #endif
389 #endif // CONFIG_RUNTIME_CPUDETECT
390 }
391
392 char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]){
393 char vendor[13];
394 char *retname;
395 int i;
396
397 if (NULL==(retname=malloc(256))) {
398 mp_msg(MSGT_CPUDETECT,MSGL_FATAL,"Error: GetCpuFriendlyName() not enough memory\n");
399 exit(1);
400 }
401 retname[0] = '\0';
402
403 sprintf(vendor,"%.4s%.4s%.4s",(char*)(regs+1),(char*)(regs+3),(char*)(regs+2));
404
405 do_cpuid(0x80000000,regs);
406 if (regs[0] >= 0x80000004)
407 {
408 // CPU has built-in namestring
409 for (i = 0x80000002; i <= 0x80000004; i++)
410 {
411 do_cpuid(i, regs);
412 strncat(retname, (char*)regs, 16);
413 }
414 }
415 return retname;
416 }
417
418 #else /* ARCH_X86 */ 418 #else /* ARCH_X86 */
419 419
420 #ifdef __APPLE__ 420 #ifdef __APPLE__
421 #include <sys/sysctl.h> 421 #include <sys/sysctl.h>
422 #elif defined(__AMIGAOS4__) 422 #elif defined(__AMIGAOS4__)