not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / ksplash / ksplashx / kcpuinfo.cpp
blob31d533b9e8f7d45513f8adb6803b3813678af5ad
1 /*
2 * This file is part of the KDE libraries
3 * Copyright (C) 2003 Fredrik Höglund <fredrik@kde.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <csignal>
28 #include <csetjmp>
30 #include <config-workspace.h>
31 #include "kcpuinfo.h"
34 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
35 # define HAVE_GNU_INLINE_ASM
36 #endif
39 // Copied from kdecore/kglobal.h
40 #if __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 > 2)
41 # define KDE_NO_EXPORT __attribute__ ((visibility("hidden")))
42 #else
43 # define KDE_NO_EXPORT
44 #endif
46 typedef void (*kde_sighandler_t) (int);
48 #ifdef __i386__
49 #ifdef HAVE_X86_SSE
50 static jmp_buf env;
52 // Sighandler for the SSE OS support check
53 static void sighandler( int )
55 std::longjmp( env, 1 );
57 #endif
58 #endif
60 #ifdef __PPC__
61 static sigjmp_buf jmpbuf;
62 static sig_atomic_t canjump = 0;
64 static void sigill_handler( int sig )
66 if ( !canjump ) {
67 signal( sig, SIG_DFL );
68 raise( sig );
70 canjump = 0;
71 siglongjmp( jmpbuf, 1 );
73 #endif
75 static int getCpuFeatures()
77 volatile int features = 0;
79 #if defined( HAVE_GNU_INLINE_ASM )
80 #if defined( __i386__ )
81 bool haveCPUID = false;
82 bool have3DNOW = false;
83 int result = 0;
85 // First check if the CPU supports the CPUID instruction
86 __asm__ __volatile__(
87 // Try to toggle the CPUID bit in the EFLAGS register
88 "pushf \n\t" // Push the EFLAGS register onto the stack
89 "popl %%ecx \n\t" // Pop the value into ECX
90 "movl %%ecx, %%edx \n\t" // Copy ECX to EDX
91 "xorl $0x00200000, %%ecx \n\t" // Toggle bit 21 (CPUID) in ECX
92 "pushl %%ecx \n\t" // Push the modified value onto the stack
93 "popf \n\t" // Pop it back into EFLAGS
95 // Check if the CPUID bit was successfully toggled
96 "pushf \n\t" // Push EFLAGS back onto the stack
97 "popl %%ecx \n\t" // Pop the value into ECX
98 "xorl %%eax, %%eax \n\t" // Zero out the EAX register
99 "cmpl %%ecx, %%edx \n\t" // Compare ECX with EDX
100 "je .Lno_cpuid_support%= \n\t" // Jump if they're identical
101 "movl $1, %%eax \n\t" // Set EAX to true
102 ".Lno_cpuid_support%=: \n\t"
103 : "=a"(haveCPUID) : : "%ecx", "%edx" );
105 // If we don't have CPUID we won't have the other extensions either
106 if ( ! haveCPUID )
107 return 0L;
109 // Execute CPUID with the feature request bit set
110 __asm__ __volatile__(
111 "pushl %%ebx \n\t" // Save EBX
112 "movl $1, %%eax \n\t" // Set EAX to 1 (features request)
113 "cpuid \n\t" // Call CPUID
114 "popl %%ebx \n\t" // Restore EBX
115 : "=d"(result) : : "%eax", "%ecx" );
117 // Test bit 23 (MMX support)
118 if ( result & 0x00800000 )
119 features |= KCPUInfo::IntelMMX;
121 __asm__ __volatile__(
122 "pushl %%ebx \n\t"
123 "movl $0x80000000, %%eax \n\t"
124 "cpuid \n\t"
125 "cmpl $0x80000000, %%eax \n\t"
126 "jbe .Lno_extended%= \n\t"
127 "movl $0x80000001, %%eax \n\t"
128 "cpuid \n\t"
129 "test $0x80000000, %%edx \n\t"
130 "jz .Lno_extended%= \n\t"
131 "movl $1, %%eax \n\t" // // Set EAX to true
132 ".Lno_extended%=: \n\t"
133 "popl %%ebx \n\t" // Restore EBX
134 : "=a"(have3DNOW) : );
136 if ( have3DNOW )
137 features |= KCPUInfo::AMD3DNOW;
139 #ifdef HAVE_X86_SSE
140 // Test bit 25 (SSE support)
141 if ( result & 0x00200000 ) {
142 features |= KCPUInfo::IntelSSE;
144 // OS support test for SSE.
145 // Install our own sighandler for SIGILL.
146 kde_sighandler_t oldhandler = std::signal( SIGILL, sighandler );
148 // Try executing an SSE insn to see if we get a SIGILL
149 if ( setjmp( env ) )
150 features ^= KCPUInfo::IntelSSE; // The OS support test failed
151 else
152 __asm__ __volatile__("xorps %xmm0, %xmm0");
154 // Restore the default sighandler
155 std::signal( SIGILL, oldhandler );
157 // Test bit 26 (SSE2 support)
158 if ( (result & 0x00400000) && (features & KCPUInfo::IntelSSE) )
159 features |= KCPUInfo::IntelSSE2;
161 // Note: The OS requirements for SSE2 are the same as for SSE
162 // so we don't have to do any additional tests for that.
164 #endif // HAVE_X86_SSE
165 #elif defined __PPC__ && defined HAVE_PPC_ALTIVEC
166 signal( SIGILL, sigill_handler );
167 if ( sigsetjmp( jmpbuf, 1 ) ) {
168 signal( SIGILL, SIG_DFL );
169 } else {
170 canjump = 1;
171 __asm__ __volatile__( "mtspr 256, %0\n\t"
172 "vand %%v0, %%v0, %%v0"
173 : /* none */
174 : "r" (-1) );
175 signal( SIGILL, SIG_DFL );
176 features |= KCPUInfo::AltiVec;
178 #endif // __i386__
179 #endif //HAVE_GNU_INLINE_ASM
181 return features;
184 unsigned int KCPUInfo::s_features = getCpuFeatures();