Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1891 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 
27
 
28
#if defined(USE_ARM_SIMD) && defined(_MSC_VER)
29
/* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */
30
#include 
31
#endif
32
 
33
#include "pixman-private.h"
34
 
35
#ifdef USE_VMX
36
 
37
/* The CPU detection code needs to be in a file not compiled with
38
 * "-maltivec -mabi=altivec", as gcc would try to save vector register
39
 * across function calls causing SIGILL on cpus without Altivec/vmx.
40
 */
41
static pixman_bool_t initialized = FALSE;
42
static volatile pixman_bool_t have_vmx = TRUE;
43
 
44
#ifdef __APPLE__
45
#include 
46
 
47
static pixman_bool_t
48
pixman_have_vmx (void)
49
{
50
    if (!initialized)
51
    {
52
	size_t length = sizeof(have_vmx);
53
	int error =
54
	    sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0);
55
 
56
	if (error)
57
	    have_vmx = FALSE;
58
 
59
	initialized = TRUE;
60
    }
61
    return have_vmx;
62
}
63
 
64
#elif defined (__OpenBSD__)
65
#include 
66
#include 
67
#include 
68
 
69
static pixman_bool_t
70
pixman_have_vmx (void)
71
{
72
    if (!initialized)
73
    {
74
	int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC };
75
	size_t length = sizeof(have_vmx);
76
	int error =
77
	    sysctl (mib, 2, &have_vmx, &length, NULL, 0);
78
 
79
	if (error != 0)
80
	    have_vmx = FALSE;
81
 
82
	initialized = TRUE;
83
    }
84
    return have_vmx;
85
}
86
 
87
#elif defined (__linux__)
88
#include 
89
#include 
90
#include 
91
#include 
92
#include 
93
#include 
94
#include 
95
 
96
static pixman_bool_t
97
pixman_have_vmx (void)
98
{
99
    if (!initialized)
100
    {
101
	char fname[64];
102
	unsigned long buf[64];
103
	ssize_t count = 0;
104
	pid_t pid;
105
	int fd, i;
106
 
107
	pid = getpid ();
108
	snprintf (fname, sizeof(fname) - 1, "/proc/%d/auxv", pid);
109
 
110
	fd = open (fname, O_RDONLY);
111
	if (fd >= 0)
112
	{
113
	    for (i = 0; i <= (count / sizeof(unsigned long)); i += 2)
114
	    {
115
		/* Read more if buf is empty... */
116
		if (i == (count / sizeof(unsigned long)))
117
		{
118
		    count = read (fd, buf, sizeof(buf));
119
		    if (count <= 0)
120
			break;
121
		    i = 0;
122
		}
123
 
124
		if (buf[i] == AT_HWCAP)
125
		{
126
		    have_vmx = !!(buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC);
127
		    initialized = TRUE;
128
		    break;
129
		}
130
		else if (buf[i] == AT_NULL)
131
		{
132
		    break;
133
		}
134
	    }
135
	    close (fd);
136
	}
137
    }
138
    if (!initialized)
139
    {
140
	/* Something went wrong. Assume 'no' rather than playing
141
	   fragile tricks with catching SIGILL. */
142
	have_vmx = FALSE;
143
	initialized = TRUE;
144
    }
145
 
146
    return have_vmx;
147
}
148
 
149
#else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */
150
#include 
151
#include 
152
 
153
static jmp_buf jump_env;
154
 
155
static void
156
vmx_test (int        sig,
157
	  siginfo_t *si,
158
	  void *     unused)
159
{
160
    longjmp (jump_env, 1);
161
}
162
 
163
static pixman_bool_t
164
pixman_have_vmx (void)
165
{
166
    struct sigaction sa, osa;
167
    int jmp_result;
168
 
169
    if (!initialized)
170
    {
171
	sa.sa_flags = SA_SIGINFO;
172
	sigemptyset (&sa.sa_mask);
173
	sa.sa_sigaction = vmx_test;
174
	sigaction (SIGILL, &sa, &osa);
175
	jmp_result = setjmp (jump_env);
176
	if (jmp_result == 0)
177
	{
178
	    asm volatile ( "vor 0, 0, 0" );
179
	}
180
	sigaction (SIGILL, &osa, NULL);
181
	have_vmx = (jmp_result == 0);
182
	initialized = TRUE;
183
    }
184
    return have_vmx;
185
}
186
 
187
#endif /* __APPLE__ */
188
#endif /* USE_VMX */
189
 
190
#if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON)
191
 
192
#if defined(_MSC_VER)
193
 
194
#if defined(USE_ARM_SIMD)
195
extern int pixman_msvc_try_arm_simd_op ();
196
 
197
pixman_bool_t
198
pixman_have_arm_simd (void)
199
{
200
    static pixman_bool_t initialized = FALSE;
201
    static pixman_bool_t have_arm_simd = FALSE;
202
 
203
    if (!initialized)
204
    {
205
	__try {
206
	    pixman_msvc_try_arm_simd_op ();
207
	    have_arm_simd = TRUE;
208
	} __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) {
209
	    have_arm_simd = FALSE;
210
	}
211
	initialized = TRUE;
212
    }
213
 
214
    return have_arm_simd;
215
}
216
 
217
#endif /* USE_ARM_SIMD */
218
 
219
#if defined(USE_ARM_NEON)
220
extern int pixman_msvc_try_arm_neon_op ();
221
 
222
pixman_bool_t
223
pixman_have_arm_neon (void)
224
{
225
    static pixman_bool_t initialized = FALSE;
226
    static pixman_bool_t have_arm_neon = FALSE;
227
 
228
    if (!initialized)
229
    {
230
	__try
231
	{
232
	    pixman_msvc_try_arm_neon_op ();
233
	    have_arm_neon = TRUE;
234
	}
235
	__except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION)
236
	{
237
	    have_arm_neon = FALSE;
238
	}
239
	initialized = TRUE;
240
    }
241
 
242
    return have_arm_neon;
243
}
244
 
245
#endif /* USE_ARM_NEON */
246
 
247
#else /* linux ELF */
248
 
249
#include 
250
#include 
251
#include 
252
#include 
253
#include 
254
#include 
255
#include 
256
#include 
257
 
258
static pixman_bool_t arm_has_v7 = FALSE;
259
static pixman_bool_t arm_has_v6 = FALSE;
260
static pixman_bool_t arm_has_vfp = FALSE;
261
static pixman_bool_t arm_has_neon = FALSE;
262
static pixman_bool_t arm_has_iwmmxt = FALSE;
263
static pixman_bool_t arm_tests_initialized = FALSE;
264
 
265
static void
266
pixman_arm_read_auxv ()
267
{
268
    int fd;
269
    Elf32_auxv_t aux;
270
 
271
    fd = open ("/proc/self/auxv", O_RDONLY);
272
    if (fd >= 0)
273
    {
274
	while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t))
275
	{
276
	    if (aux.a_type == AT_HWCAP)
277
	    {
278
		uint32_t hwcap = aux.a_un.a_val;
279
		/* hardcode these values to avoid depending on specific
280
		 * versions of the hwcap header, e.g. HWCAP_NEON
281
		 */
282
		arm_has_vfp = (hwcap & 64) != 0;
283
		arm_has_iwmmxt = (hwcap & 512) != 0;
284
		/* this flag is only present on kernel 2.6.29 */
285
		arm_has_neon = (hwcap & 4096) != 0;
286
	    }
287
	    else if (aux.a_type == AT_PLATFORM)
288
	    {
289
		const char *plat = (const char*) aux.a_un.a_val;
290
		if (strncmp (plat, "v7l", 3) == 0)
291
		{
292
		    arm_has_v7 = TRUE;
293
		    arm_has_v6 = TRUE;
294
		}
295
		else if (strncmp (plat, "v6l", 3) == 0)
296
		{
297
		    arm_has_v6 = TRUE;
298
		}
299
	    }
300
	}
301
	close (fd);
302
    }
303
 
304
    arm_tests_initialized = TRUE;
305
}
306
 
307
#if defined(USE_ARM_SIMD)
308
pixman_bool_t
309
pixman_have_arm_simd (void)
310
{
311
    if (!arm_tests_initialized)
312
	pixman_arm_read_auxv ();
313
 
314
    return arm_has_v6;
315
}
316
 
317
#endif /* USE_ARM_SIMD */
318
 
319
#if defined(USE_ARM_NEON)
320
pixman_bool_t
321
pixman_have_arm_neon (void)
322
{
323
    if (!arm_tests_initialized)
324
	pixman_arm_read_auxv ();
325
 
326
    return arm_has_neon;
327
}
328
 
329
#endif /* USE_ARM_NEON */
330
 
331
#endif /* linux */
332
 
333
#endif /* USE_ARM_SIMD || USE_ARM_NEON */
334
 
335
#if defined(USE_MMX) || defined(USE_SSE2)
336
/* The CPU detection code needs to be in a file not compiled with
337
 * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
338
 * that would lead to SIGILL instructions on old CPUs that don't have
339
 * it.
340
 */
341
#if !defined(__amd64__) && !defined(__x86_64__) && !defined(_M_AMD64)
342
 
343
#ifdef HAVE_GETISAX
344
#include 
345
#endif
346
 
347
typedef enum
348
{
349
    NO_FEATURES = 0,
350
    MMX = 0x1,
351
    MMX_EXTENSIONS = 0x2,
352
    SSE = 0x6,
353
    SSE2 = 0x8,
354
    CMOV = 0x10
355
} cpu_features_t;
356
 
357
 
358
static unsigned int
359
detect_cpu_features (void)
360
{
361
    unsigned int features = 0;
362
    unsigned int result = 0;
363
 
364
#ifdef HAVE_GETISAX
365
    if (getisax (&result, 1))
366
    {
367
	if (result & AV_386_CMOV)
368
	    features |= CMOV;
369
	if (result & AV_386_MMX)
370
	    features |= MMX;
371
	if (result & AV_386_AMD_MMX)
372
	    features |= MMX_EXTENSIONS;
373
	if (result & AV_386_SSE)
374
	    features |= SSE;
375
	if (result & AV_386_SSE2)
376
	    features |= SSE2;
377
    }
378
#else
379
    char vendor[13];
380
#ifdef _MSC_VER
381
    int vendor0 = 0, vendor1, vendor2;
382
#endif
383
    vendor[0] = 0;
384
    vendor[12] = 0;
385
 
386
#ifdef __GNUC__
387
    /* see p. 118 of amd64 instruction set manual Vol3 */
388
    /* We need to be careful about the handling of %ebx and
389
     * %esp here. We can't declare either one as clobbered
390
     * since they are special registers (%ebx is the "PIC
391
     * register" holding an offset to global data, %esp the
392
     * stack pointer), so we need to make sure they have their
393
     * original values when we access the output operands.
394
     */
395
    __asm__ (
396
        "pushf\n"
397
        "pop %%eax\n"
398
        "mov %%eax, %%ecx\n"
399
        "xor $0x00200000, %%eax\n"
400
        "push %%eax\n"
401
        "popf\n"
402
        "pushf\n"
403
        "pop %%eax\n"
404
        "mov $0x0, %%edx\n"
405
        "xor %%ecx, %%eax\n"
406
        "jz 1f\n"
407
 
408
        "mov $0x00000000, %%eax\n"
409
        "push %%ebx\n"
410
        "cpuid\n"
411
        "mov %%ebx, %%eax\n"
412
        "pop %%ebx\n"
413
        "mov %%eax, %1\n"
414
        "mov %%edx, %2\n"
415
        "mov %%ecx, %3\n"
416
        "mov $0x00000001, %%eax\n"
417
        "push %%ebx\n"
418
        "cpuid\n"
419
        "pop %%ebx\n"
420
        "1:\n"
421
        "mov %%edx, %0\n"
422
	: "=r" (result),
423
        "=m" (vendor[0]),
424
        "=m" (vendor[4]),
425
        "=m" (vendor[8])
426
	:
427
	: "%eax", "%ecx", "%edx"
428
        );
429
 
430
#elif defined (_MSC_VER)
431
 
432
    _asm {
433
	pushfd
434
	pop eax
435
	mov ecx, eax
436
	xor eax, 00200000h
437
	push eax
438
	popfd
439
	pushfd
440
	pop eax
441
	mov edx, 0
442
	xor eax, ecx
443
	jz nocpuid
444
 
445
	mov eax, 0
446
	push ebx
447
	cpuid
448
	mov eax, ebx
449
	pop ebx
450
	mov vendor0, eax
451
	mov vendor1, edx
452
	mov vendor2, ecx
453
	mov eax, 1
454
	push ebx
455
	cpuid
456
	pop ebx
457
    nocpuid:
458
	mov result, edx
459
    }
460
    memmove (vendor + 0, &vendor0, 4);
461
    memmove (vendor + 4, &vendor1, 4);
462
    memmove (vendor + 8, &vendor2, 4);
463
 
464
#else
465
#   error unsupported compiler
466
#endif
467
 
468
    features = 0;
469
    if (result)
470
    {
471
	/* result now contains the standard feature bits */
472
	if (result & (1 << 15))
473
	    features |= CMOV;
474
	if (result & (1 << 23))
475
	    features |= MMX;
476
	if (result & (1 << 25))
477
	    features |= SSE;
478
	if (result & (1 << 26))
479
	    features |= SSE2;
480
	if ((features & MMX) && !(features & SSE) &&
481
	    (strcmp (vendor, "AuthenticAMD") == 0 ||
482
	     strcmp (vendor, "Geode by NSC") == 0))
483
	{
484
	    /* check for AMD MMX extensions */
485
#ifdef __GNUC__
486
	    __asm__ (
487
	        "	push %%ebx\n"
488
	        "	mov $0x80000000, %%eax\n"
489
	        "	cpuid\n"
490
	        "	xor %%edx, %%edx\n"
491
	        "	cmp $0x1, %%eax\n"
492
	        "	jge 2f\n"
493
	        "	mov $0x80000001, %%eax\n"
494
	        "	cpuid\n"
495
	        "2:\n"
496
	        "	pop %%ebx\n"
497
	        "	mov %%edx, %0\n"
498
		: "=r" (result)
499
		:
500
		: "%eax", "%ecx", "%edx"
501
	        );
502
#elif defined _MSC_VER
503
	    _asm {
504
		push ebx
505
		mov eax, 80000000h
506
		cpuid
507
		xor edx, edx
508
		cmp eax, 1
509
		jge notamd
510
		mov eax, 80000001h
511
		cpuid
512
	    notamd:
513
		pop ebx
514
		mov result, edx
515
	    }
516
#endif
517
	    if (result & (1 << 22))
518
		features |= MMX_EXTENSIONS;
519
	}
520
    }
521
#endif /* HAVE_GETISAX */
522
 
523
    return features;
524
}
525
 
526
static pixman_bool_t
527
pixman_have_mmx (void)
528
{
529
    static pixman_bool_t initialized = FALSE;
530
    static pixman_bool_t mmx_present;
531
 
532
    if (!initialized)
533
    {
534
	unsigned int features = detect_cpu_features ();
535
	mmx_present = (features & (MMX | MMX_EXTENSIONS)) == (MMX | MMX_EXTENSIONS);
536
	initialized = TRUE;
537
    }
538
 
539
    return mmx_present;
540
}
541
 
542
#ifdef USE_SSE2
543
static pixman_bool_t
544
pixman_have_sse2 (void)
545
{
546
    static pixman_bool_t initialized = FALSE;
547
    static pixman_bool_t sse2_present;
548
 
549
    if (!initialized)
550
    {
551
	unsigned int features = detect_cpu_features ();
552
	sse2_present = (features & (MMX | MMX_EXTENSIONS | SSE | SSE2)) == (MMX | MMX_EXTENSIONS | SSE | SSE2);
553
	initialized = TRUE;
554
    }
555
 
556
    return sse2_present;
557
}
558
 
559
#endif
560
 
561
#else /* __amd64__ */
562
#ifdef USE_MMX
563
#define pixman_have_mmx() TRUE
564
#endif
565
#ifdef USE_SSE2
566
#define pixman_have_sse2() TRUE
567
#endif
568
#endif /* __amd64__ */
569
#endif
570
 
571
pixman_implementation_t *
572
_pixman_choose_implementation (void)
573
{
574
#ifdef USE_SSE2
575
    if (pixman_have_sse2 ())
576
	return _pixman_implementation_create_sse2 ();
577
#endif
578
#ifdef USE_MMX
579
    if (pixman_have_mmx ())
580
	return _pixman_implementation_create_mmx ();
581
#endif
582
 
583
#ifdef USE_ARM_NEON
584
    if (pixman_have_arm_neon ())
585
	return _pixman_implementation_create_arm_neon ();
586
#endif
587
#ifdef USE_ARM_SIMD
588
    if (pixman_have_arm_simd ())
589
	return _pixman_implementation_create_arm_simd ();
590
#endif
591
#ifdef USE_VMX
592
    if (pixman_have_vmx ())
593
	return _pixman_implementation_create_vmx ();
594
#endif
595
 
596
    return _pixman_implementation_create_fast_path ();
597
}
598