Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
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 
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
have_cpuid (void)
79
{
80
#if _PIXMAN_X86_64 || defined (_MSC_VER)
81
 
82
    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
static void
110
pixman_cpuid (uint32_t feature,
111
	      uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
112
{
113
#if defined (__GNUC__)
114
 
115
#if _PIXMAN_X86_64
116
    __asm__ volatile (
117
        "cpuid"				"\n\t"
118
	: "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d)
119
	: "a" (feature));
120
#else
121
    /* On x86-32 we need to be careful about the handling of %ebx
122
     * and %esp. We can't declare either one as clobbered
123
     * since they are special registers (%ebx is the "PIC
124
     * register" holding an offset to global data, %esp the
125
     * stack pointer), so we need to make sure that %ebx is
126
     * preserved, and that %esp has its original value when
127
     * accessing the output operands.
128
     */
129
    __asm__ volatile (
130
	"xchg %%ebx, %1"		"\n\t"
131
	"cpuid"				"\n\t"
132
	"xchg %%ebx, %1"		"\n\t"
133
	: "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
134
	: "a" (feature));
135
#endif
136
 
137
#elif defined (_MSC_VER)
138
    int info[4];
139
 
140
    __cpuid (info, feature);
141
 
142
    *a = info[0];
143
    *b = info[1];
144
    *c = info[2];
145
    *d = info[3];
146
#else
147
#error Unknown compiler
148
#endif
149
}
150
 
151
static cpu_features_t
152
detect_cpu_features (void)
153
{
154
    uint32_t a, b, c, d;
155
    cpu_features_t features = 0;
156
 
157
    if (!have_cpuid())
158
	return features;
159
 
160
    /* Get feature bits */
161
    pixman_cpuid (0x01, &a, &b, &c, &d);
162
    if (d & (1 << 15))
163
	features |= X86_CMOV;
164
    if (d & (1 << 23))
165
	features |= X86_MMX;
166
    if (d & (1 << 25))
167
	features |= X86_SSE;
168
    if (d & (1 << 26))
169
	features |= X86_SSE2;
170
 
171
    /* Check for AMD specific features */
172
    if ((features & X86_MMX) && !(features & X86_SSE))
173
    {
174
	char vendor[13];
175
 
176
	/* Get vendor string */
177
	memset (vendor, 0, sizeof vendor);
178
 
179
	pixman_cpuid (0x00, &a, &b, &c, &d);
180
	memcpy (vendor + 0, &b, 4);
181
	memcpy (vendor + 4, &d, 4);
182
	memcpy (vendor + 8, &c, 4);
183
 
184
	if (strcmp (vendor, "AuthenticAMD") == 0 ||
185
	    strcmp (vendor, "Geode by NSC") == 0)
186
	{
187
	    pixman_cpuid (0x80000000, &a, &b, &c, &d);
188
	    if (a >= 0x80000001)
189
	    {
190
		pixman_cpuid (0x80000001, &a, &b, &c, &d);
191
 
192
		if (d & (1 << 22))
193
		    features |= X86_MMX_EXTENSIONS;
194
	    }
195
	}
196
    }
197
 
198
    return features;
199
}
200
 
201
#endif
202
 
203
static pixman_bool_t
204
have_feature (cpu_features_t feature)
205
{
206
    static pixman_bool_t initialized;
207
    static cpu_features_t features;
208
 
209
    if (!initialized)
210
    {
211
	features = detect_cpu_features();
212
	initialized = TRUE;
213
    }
214
 
215
    return (features & feature) == feature;
216
}
217
 
218
#endif
219
 
220
pixman_implementation_t *
221
_pixman_x86_get_implementations (pixman_implementation_t *imp)
222
{
223
#define MMX_BITS  (X86_MMX | X86_MMX_EXTENSIONS)
224
#define SSE2_BITS (X86_MMX | X86_MMX_EXTENSIONS | X86_SSE | X86_SSE2)
225
 
226
#ifdef USE_X86_MMX
227
    if (!_pixman_disabled ("mmx") && have_feature (MMX_BITS))
228
	imp = _pixman_implementation_create_mmx (imp);
229
#endif
230
 
231
#ifdef USE_SSE2
232
    if (!_pixman_disabled ("sse2") && have_feature (SSE2_BITS))
233
	imp = _pixman_implementation_create_sse2 (imp);
234
#endif
235
 
236
    return imp;
237
}