Line data Source code
1 : /*
2 : * Copyright © 2000 SuSE, Inc.
3 : * Copyright © 2007 Red Hat, Inc.
4 : *
5 : * Permission to use, copy, modify, distribute, and sell this software and its
6 : * documentation for any purpose is hereby granted without fee, provided that
7 : * the above copyright notice appear in all copies and that both that
8 : * copyright notice and this permission notice appear in supporting
9 : * documentation, and that the name of SuSE not be used in advertising or
10 : * publicity pertaining to distribution of the software without specific,
11 : * written prior permission. SuSE makes no representations about the
12 : * suitability of this software for any purpose. It is provided "as is"
13 : * without express or implied warranty.
14 : *
15 : * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17 : * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 : * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 : * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 : */
22 : #ifdef HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 :
26 : #include "pixman-private.h"
27 :
28 : #if defined(USE_X86_MMX) || defined (USE_SSE2)
29 :
30 : /* The CPU detection code needs to be in a file not compiled with
31 : * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
32 : * that would lead to SIGILL instructions on old CPUs that don't have
33 : * it.
34 : */
35 :
36 : typedef enum
37 : {
38 : X86_MMX = (1 << 0),
39 : X86_MMX_EXTENSIONS = (1 << 1),
40 : X86_SSE = (1 << 2) | X86_MMX_EXTENSIONS,
41 : X86_SSE2 = (1 << 3),
42 : X86_CMOV = (1 << 4)
43 : } cpu_features_t;
44 :
45 : #ifdef HAVE_GETISAX
46 :
47 : #include <sys/auxv.h>
48 :
49 : static cpu_features_t
50 : detect_cpu_features (void)
51 : {
52 : cpu_features_t features = 0;
53 : unsigned int result = 0;
54 :
55 : if (getisax (&result, 1))
56 : {
57 : if (result & AV_386_CMOV)
58 : features |= X86_CMOV;
59 : if (result & AV_386_MMX)
60 : features |= X86_MMX;
61 : if (result & AV_386_AMD_MMX)
62 : features |= X86_MMX_EXTENSIONS;
63 : if (result & AV_386_SSE)
64 : features |= X86_SSE;
65 : if (result & AV_386_SSE2)
66 : features |= X86_SSE2;
67 : }
68 :
69 : return features;
70 : }
71 :
72 : #else
73 :
74 : #define _PIXMAN_X86_64 \
75 : (defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
76 :
77 : static pixman_bool_t
78 1 : have_cpuid (void)
79 : {
80 : #if _PIXMAN_X86_64 || defined (_MSC_VER)
81 :
82 1 : return TRUE;
83 :
84 : #elif defined (__GNUC__)
85 : uint32_t result;
86 :
87 : __asm__ volatile (
88 : "pushf" "\n\t"
89 : "pop %%eax" "\n\t"
90 : "mov %%eax, %%ecx" "\n\t"
91 : "xor $0x00200000, %%eax" "\n\t"
92 : "push %%eax" "\n\t"
93 : "popf" "\n\t"
94 : "pushf" "\n\t"
95 : "pop %%eax" "\n\t"
96 : "xor %%ecx, %%eax" "\n\t"
97 : "mov %%eax, %0" "\n\t"
98 : : "=r" (result)
99 : :
100 : : "%eax", "%ecx");
101 :
102 : return !!result;
103 :
104 : #else
105 : #error "Unknown compiler"
106 : #endif
107 : }
108 :
109 : #ifdef _MSC_VER
110 : #include <intrin.h> /* for __cpuid */
111 : #endif
112 :
113 : static void
114 1 : pixman_cpuid (uint32_t feature,
115 : uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
116 : {
117 : #if defined (__GNUC__)
118 :
119 : #if _PIXMAN_X86_64
120 1 : __asm__ volatile (
121 : "cpuid" "\n\t"
122 : : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
123 : : "a" (feature));
124 : #else
125 : /* On x86-32 we need to be careful about the handling of %ebx
126 : * and %esp. We can't declare either one as clobbered
127 : * since they are special registers (%ebx is the "PIC
128 : * register" holding an offset to global data, %esp the
129 : * stack pointer), so we need to make sure that %ebx is
130 : * preserved, and that %esp has its original value when
131 : * accessing the output operands.
132 : */
133 : __asm__ volatile (
134 : "xchg %%ebx, %1" "\n\t"
135 : "cpuid" "\n\t"
136 : "xchg %%ebx, %1" "\n\t"
137 : : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
138 : : "a" (feature));
139 : #endif
140 :
141 : #elif defined (_MSC_VER)
142 : int info[4];
143 :
144 : __cpuid (info, feature);
145 :
146 : *a = info[0];
147 : *b = info[1];
148 : *c = info[2];
149 : *d = info[3];
150 : #else
151 : #error Unknown compiler
152 : #endif
153 1 : }
154 :
155 : static cpu_features_t
156 1 : detect_cpu_features (void)
157 : {
158 : uint32_t a, b, c, d;
159 1 : cpu_features_t features = 0;
160 :
161 1 : if (!have_cpuid())
162 0 : return features;
163 :
164 : /* Get feature bits */
165 1 : pixman_cpuid (0x01, &a, &b, &c, &d);
166 1 : if (d & (1 << 15))
167 1 : features |= X86_CMOV;
168 1 : if (d & (1 << 23))
169 1 : features |= X86_MMX;
170 1 : if (d & (1 << 25))
171 1 : features |= X86_SSE;
172 1 : if (d & (1 << 26))
173 1 : features |= X86_SSE2;
174 :
175 : /* Check for AMD specific features */
176 1 : if ((features & X86_MMX) && !(features & X86_SSE))
177 : {
178 : char vendor[13];
179 :
180 : /* Get vendor string */
181 0 : memset (vendor, 0, sizeof vendor);
182 :
183 0 : pixman_cpuid (0x00, &a, &b, &c, &d);
184 0 : memcpy (vendor + 0, &b, 4);
185 0 : memcpy (vendor + 4, &d, 4);
186 0 : memcpy (vendor + 8, &c, 4);
187 :
188 0 : if (strcmp (vendor, "AuthenticAMD") == 0 ||
189 0 : strcmp (vendor, "Geode by NSC") == 0)
190 : {
191 0 : pixman_cpuid (0x80000000, &a, &b, &c, &d);
192 0 : if (a >= 0x80000001)
193 : {
194 0 : pixman_cpuid (0x80000001, &a, &b, &c, &d);
195 :
196 0 : if (d & (1 << 22))
197 0 : features |= X86_MMX_EXTENSIONS;
198 : }
199 : }
200 : }
201 :
202 1 : return features;
203 : }
204 :
205 : #endif
206 :
207 : static pixman_bool_t
208 1 : have_feature (cpu_features_t feature)
209 : {
210 : static pixman_bool_t initialized;
211 : static cpu_features_t features;
212 :
213 1 : if (!initialized)
214 : {
215 1 : features = detect_cpu_features();
216 1 : initialized = TRUE;
217 : }
218 :
219 1 : return (features & feature) == feature;
220 : }
221 :
222 : #endif
223 :
224 : pixman_implementation_t *
225 1 : _pixman_x86_get_implementations (pixman_implementation_t *imp)
226 : {
227 : #define MMX_BITS (X86_MMX | X86_MMX_EXTENSIONS)
228 : #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
229 :
230 : #ifdef USE_X86_MMX
231 : if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
232 : imp = _pixman_implementation_create_mmx (imp);
233 : #endif
234 :
235 : #ifdef USE_SSE2
236 1 : if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
237 1 : imp = _pixman_implementation_create_sse2 (imp);
238 : #endif
239 :
240 1 : return imp;
241 : }
|