Add qemu 2.4.0
[kvmfornfv.git] / qemu / pixman / pixman / pixman-x86.c
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) || defined (USE_SSSE3)
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     X86_SSSE3                   = (1 << 5)
44 } cpu_features_t;
45
46 #ifdef HAVE_GETISAX
47
48 #include <sys/auxv.h>
49
50 static cpu_features_t
51 detect_cpu_features (void)
52 {
53     cpu_features_t features = 0;
54     unsigned int result = 0;
55
56     if (getisax (&result, 1))
57     {
58         if (result & AV_386_CMOV)
59             features |= X86_CMOV;
60         if (result & AV_386_MMX)
61             features |= X86_MMX;
62         if (result & AV_386_AMD_MMX)
63             features |= X86_MMX_EXTENSIONS;
64         if (result & AV_386_SSE)
65             features |= X86_SSE;
66         if (result & AV_386_SSE2)
67             features |= X86_SSE2;
68         if (result & AV_386_SSSE3)
69             features |= X86_SSSE3;
70     }
71
72     return features;
73 }
74
75 #else
76
77 #define _PIXMAN_X86_64                                                  \
78     (defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64))
79
80 static pixman_bool_t
81 have_cpuid (void)
82 {
83 #if _PIXMAN_X86_64 || defined (_MSC_VER)
84
85     return TRUE;
86
87 #elif defined (__GNUC__)
88     uint32_t result;
89
90     __asm__ volatile (
91         "pushf"                         "\n\t"
92         "pop %%eax"                     "\n\t"
93         "mov %%eax, %%ecx"              "\n\t"
94         "xor $0x00200000, %%eax"        "\n\t"
95         "push %%eax"                    "\n\t"
96         "popf"                          "\n\t"
97         "pushf"                         "\n\t"
98         "pop %%eax"                     "\n\t"
99         "xor %%ecx, %%eax"              "\n\t"
100         "mov %%eax, %0"                 "\n\t"
101         : "=r" (result)
102         :
103         : "%eax", "%ecx");
104
105     return !!result;
106
107 #else
108 #error "Unknown compiler"
109 #endif
110 }
111
112 static void
113 pixman_cpuid (uint32_t feature,
114               uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
115 {
116 #if defined (__GNUC__)
117
118 #if _PIXMAN_X86_64
119     __asm__ volatile (
120         "cpuid"                         "\n\t"
121         : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
122         : "a" (feature));
123 #else
124     /* On x86-32 we need to be careful about the handling of %ebx
125      * and %esp. We can't declare either one as clobbered
126      * since they are special registers (%ebx is the "PIC
127      * register" holding an offset to global data, %esp the
128      * stack pointer), so we need to make sure that %ebx is
129      * preserved, and that %esp has its original value when
130      * accessing the output operands.
131      */
132     __asm__ volatile (
133         "xchg %%ebx, %1"                "\n\t"
134         "cpuid"                         "\n\t"
135         "xchg %%ebx, %1"                "\n\t"
136         : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
137         : "a" (feature));
138 #endif
139
140 #elif defined (_MSC_VER)
141     int info[4];
142
143     __cpuid (info, feature);
144
145     *a = info[0];
146     *b = info[1];
147     *c = info[2];
148     *d = info[3];
149 #else
150 #error Unknown compiler
151 #endif
152 }
153
154 static cpu_features_t
155 detect_cpu_features (void)
156 {
157     uint32_t a, b, c, d;
158     cpu_features_t features = 0;
159
160     if (!have_cpuid())
161         return features;
162
163     /* Get feature bits */
164     pixman_cpuid (0x01, &a, &b, &c, &d);
165     if (d & (1 << 15))
166         features |= X86_CMOV;
167     if (d & (1 << 23))
168         features |= X86_MMX;
169     if (d & (1 << 25))
170         features |= X86_SSE;
171     if (d & (1 << 26))
172         features |= X86_SSE2;
173     if (c & (1 << 9))
174         features |= X86_SSSE3;
175
176     /* Check for AMD specific features */
177     if ((features & X86_MMX) && !(features & X86_SSE))
178     {
179         char vendor[13];
180
181         /* Get vendor string */
182         memset (vendor, 0, sizeof vendor);
183
184         pixman_cpuid (0x00, &a, &b, &c, &d);
185         memcpy (vendor + 0, &b, 4);
186         memcpy (vendor + 4, &d, 4);
187         memcpy (vendor + 8, &c, 4);
188
189         if (strcmp (vendor, "AuthenticAMD") == 0 ||
190             strcmp (vendor, "Geode by NSC") == 0)
191         {
192             pixman_cpuid (0x80000000, &a, &b, &c, &d);
193             if (a >= 0x80000001)
194             {
195                 pixman_cpuid (0x80000001, &a, &b, &c, &d);
196
197                 if (d & (1 << 22))
198                     features |= X86_MMX_EXTENSIONS;
199             }
200         }
201     }
202
203     return features;
204 }
205
206 #endif
207
208 static pixman_bool_t
209 have_feature (cpu_features_t feature)
210 {
211     static pixman_bool_t initialized;
212     static cpu_features_t features;
213
214     if (!initialized)
215     {
216         features = detect_cpu_features();
217         initialized = TRUE;
218     }
219
220     return (features & feature) == feature;
221 }
222
223 #endif
224
225 pixman_implementation_t *
226 _pixman_x86_get_implementations (pixman_implementation_t *imp)
227 {
228 #define MMX_BITS  (X86_MMX | X86_MMX_EXTENSIONS)
229 #define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
230 #define SSSE3_BITS (X86_SSE | X86_SSE2 | X86_SSSE3)
231
232 #ifdef USE_X86_MMX
233     if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
234         imp = _pixman_implementation_create_mmx (imp);
235 #endif
236
237 #ifdef USE_SSE2
238     if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
239         imp = _pixman_implementation_create_sse2 (imp);
240 #endif
241
242 #ifdef USE_SSSE3
243     if (!_pixman_disabled ("ssse3") && have_feature (SSSE3_BITS))
244         imp = _pixman_implementation_create_ssse3 (imp);
245 #endif
246
247     return imp;
248 }