Line data Source code
1 : /********************************************************************
2 : * *
3 : * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
4 : * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 : * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 : * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 : * *
8 : * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 *
9 : * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
10 : * *
11 : ********************************************************************
12 :
13 : CPU capability detection for x86 processors.
14 : Originally written by Rudolf Marek.
15 :
16 : function:
17 : last mod: $Id: x86cpu.c 17410 2010-09-21 21:53:48Z tterribe $
18 :
19 : ********************************************************************/
20 :
21 : #include "x86cpu.h"
22 :
23 : #if !defined(OC_X86_ASM)
24 : ogg_uint32_t oc_cpu_flags_get(void){
25 : return 0;
26 : }
27 : #else
28 : # if defined(__amd64__)||defined(__x86_64__)
29 : /*On x86-64, gcc seems to be able to figure out how to save %rbx for us when
30 : compiling with -fPIC.*/
31 : # define cpuid(_op,_eax,_ebx,_ecx,_edx) \
32 : __asm__ __volatile__( \
33 : "cpuid\n\t" \
34 : :[eax]"=a"(_eax),[ebx]"=b"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
35 : :"a"(_op) \
36 : :"cc" \
37 : )
38 : # else
39 : /*On x86-32, not so much.*/
40 : # define cpuid(_op,_eax,_ebx,_ecx,_edx) \
41 : __asm__ __volatile__( \
42 : "xchgl %%ebx,%[ebx]\n\t" \
43 : "cpuid\n\t" \
44 : "xchgl %%ebx,%[ebx]\n\t" \
45 : :[eax]"=a"(_eax),[ebx]"=r"(_ebx),[ecx]"=c"(_ecx),[edx]"=d"(_edx) \
46 : :"a"(_op) \
47 : :"cc" \
48 : )
49 : # endif
50 :
51 0 : static ogg_uint32_t oc_parse_intel_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
52 : ogg_uint32_t flags;
53 : /*If there isn't even MMX, give up.*/
54 0 : if(!(_edx&0x00800000))return 0;
55 0 : flags=OC_CPU_X86_MMX;
56 0 : if(_edx&0x02000000)flags|=OC_CPU_X86_MMXEXT|OC_CPU_X86_SSE;
57 0 : if(_edx&0x04000000)flags|=OC_CPU_X86_SSE2;
58 0 : if(_ecx&0x00000001)flags|=OC_CPU_X86_PNI;
59 0 : if(_ecx&0x00000100)flags|=OC_CPU_X86_SSSE3;
60 0 : if(_ecx&0x00080000)flags|=OC_CPU_X86_SSE4_1;
61 0 : if(_ecx&0x00100000)flags|=OC_CPU_X86_SSE4_2;
62 0 : return flags;
63 : }
64 :
65 0 : static ogg_uint32_t oc_parse_amd_flags(ogg_uint32_t _edx,ogg_uint32_t _ecx){
66 : ogg_uint32_t flags;
67 : /*If there isn't even MMX, give up.*/
68 0 : if(!(_edx&0x00800000))return 0;
69 0 : flags=OC_CPU_X86_MMX;
70 0 : if(_edx&0x00400000)flags|=OC_CPU_X86_MMXEXT;
71 0 : if(_edx&0x80000000)flags|=OC_CPU_X86_3DNOW;
72 0 : if(_edx&0x40000000)flags|=OC_CPU_X86_3DNOWEXT;
73 0 : if(_ecx&0x00000040)flags|=OC_CPU_X86_SSE4A;
74 0 : if(_ecx&0x00000800)flags|=OC_CPU_X86_SSE5;
75 0 : return flags;
76 : }
77 :
78 0 : ogg_uint32_t oc_cpu_flags_get(void){
79 : ogg_uint32_t flags;
80 : ogg_uint32_t eax;
81 : ogg_uint32_t ebx;
82 : ogg_uint32_t ecx;
83 : ogg_uint32_t edx;
84 : # if !defined(__amd64__)&&!defined(__x86_64__)
85 : /*Not all x86-32 chips support cpuid, so we have to check.*/
86 : __asm__ __volatile__(
87 : "pushfl\n\t"
88 : "pushfl\n\t"
89 : "popl %[a]\n\t"
90 : "movl %[a],%[b]\n\t"
91 : "xorl $0x200000,%[a]\n\t"
92 : "pushl %[a]\n\t"
93 : "popfl\n\t"
94 : "pushfl\n\t"
95 : "popl %[a]\n\t"
96 : "popfl\n\t"
97 : :[a]"=r"(eax),[b]"=r"(ebx)
98 : :
99 : :"cc"
100 : );
101 : /*No cpuid.*/
102 : if(eax==ebx)return 0;
103 : # endif
104 0 : cpuid(0,eax,ebx,ecx,edx);
105 : /* l e t n I e n i u n e G*/
106 0 : if(ecx==0x6C65746E&&edx==0x49656E69&&ebx==0x756E6547||
107 : /* 6 8 x M T e n i u n e G*/
108 0 : ecx==0x3638784D&&edx==0x54656E69&&ebx==0x756E6547){
109 : int family;
110 : int model;
111 : /*Intel, Transmeta (tested with Crusoe TM5800):*/
112 0 : cpuid(1,eax,ebx,ecx,edx);
113 0 : flags=oc_parse_intel_flags(edx,ecx);
114 0 : family=(eax>>8)&0xF;
115 0 : model=(eax>>4)&0xF;
116 : /*The SSE unit on the Pentium M and Core Duo is much slower than the MMX
117 : unit, so don't use it.*/
118 0 : if(family==6&&(model==9||model==13||model==14)){
119 0 : flags&=~(OC_CPU_X86_SSE2|OC_CPU_X86_PNI);
120 : }
121 : }
122 : /* D M A c i t n e h t u A*/
123 0 : else if(ecx==0x444D4163&&edx==0x69746E65&&ebx==0x68747541||
124 : /* C S N y b e d o e G*/
125 0 : ecx==0x43534e20&&edx==0x79622065&&ebx==0x646f6547){
126 : /*AMD, Geode:*/
127 0 : cpuid(0x80000000,eax,ebx,ecx,edx);
128 0 : if(eax<0x80000001)flags=0;
129 : else{
130 0 : cpuid(0x80000001,eax,ebx,ecx,edx);
131 0 : flags=oc_parse_amd_flags(edx,ecx);
132 : }
133 : /*Also check for SSE.*/
134 0 : cpuid(1,eax,ebx,ecx,edx);
135 0 : flags|=oc_parse_intel_flags(edx,ecx);
136 : }
137 : /*Technically some VIA chips can be configured in the BIOS to return any
138 : string here the user wants.
139 : There is a special detection method that can be used to identify such
140 : processors, but in my opinion, if the user really wants to change it, they
141 : deserve what they get.*/
142 : /* s l u a H r u a t n e C*/
143 0 : else if(ecx==0x736C7561&&edx==0x48727561&&ebx==0x746E6543){
144 : /*VIA:*/
145 : /*I only have documentation for the C7 (Esther) and Isaiah (forthcoming)
146 : chips (thanks to the engineers from Centaur Technology who provided it).
147 : These chips support Intel-like cpuid info.
148 : The C3-2 (Nehemiah) cores appear to, as well.*/
149 0 : cpuid(1,eax,ebx,ecx,edx);
150 0 : flags=oc_parse_intel_flags(edx,ecx);
151 0 : if(eax>=0x80000001){
152 : /*The (non-Nehemiah) C3 processors support AMD-like cpuid info.
153 : We need to check this even if the Intel test succeeds to pick up 3DNow!
154 : support on these processors.
155 : Unlike actual AMD processors, we cannot _rely_ on this info, since
156 : some cores (e.g., the 693 stepping of the Nehemiah) claim to support
157 : this function, yet return edx=0, despite the Intel test indicating
158 : MMX support.
159 : Therefore the features detected here are strictly added to those
160 : detected by the Intel test.*/
161 : /*TODO: How about earlier chips?*/
162 0 : cpuid(0x80000001,eax,ebx,ecx,edx);
163 : /*Note: As of the C7, this function returns Intel-style extended feature
164 : flags, not AMD-style.
165 : Currently, this only defines bits 11, 20, and 29 (0x20100800), which
166 : do not conflict with any of the AMD flags we inspect.
167 : For the remaining bits, Intel tells us, "Do not count on their value",
168 : but VIA assures us that they will all be zero (at least on the C7 and
169 : Isaiah chips).
170 : In the (unlikely) event a future processor uses bits 18, 19, 30, or 31
171 : (0xC0C00000) for something else, we will have to add code to detect
172 : the model to decide when it is appropriate to inspect them.*/
173 0 : flags|=oc_parse_amd_flags(edx,ecx);
174 : }
175 : }
176 : else{
177 : /*Implement me.*/
178 0 : flags=0;
179 : }
180 0 : return flags;
181 : }
182 : #endif
|