File indexing completed on 2024-06-09 04:00:39
0001 /* 0002 SPDX-FileCopyrightText: 2010 Kevin Ottens <ervin@kde.org> 0003 SPDX-FileCopyrightText: 2013 Patrick Spendrin <ps_ml@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 // clang-format off 0009 0010 #include "cpufeatures.h" 0011 0012 #ifndef _MSC_VER 0013 //for cpuFeatures 0014 #include <csignal> 0015 #include <csetjmp> 0016 #else 0017 #include <intrin.h> 0018 #endif 0019 #include <config-processor.h> 0020 0021 #if defined(__GNUC__) || defined(__INTEL_COMPILER) 0022 # define HAVE_GNU_INLINE_ASM 0023 #endif 0024 0025 namespace Solid 0026 { 0027 namespace Backends 0028 { 0029 namespace Shared 0030 { 0031 0032 #ifndef _MSC_VER 0033 typedef void (*kde_sighandler_t)(int); 0034 0035 #if defined( __i386__ ) || defined( __x86_64__ ) 0036 static jmp_buf env; 0037 0038 #if HAVE_X86_SSE 0039 // Sighandler for the SSE OS support check 0040 static void sighandler(int) 0041 { 0042 std::longjmp(env, 1); 0043 } 0044 #endif 0045 #endif 0046 0047 #ifdef __i386__ 0048 #define ASM_REG(reg) "%e" reg 0049 #define ASM_POP(reg) "popl %%e" reg " \n\t" 0050 #define ASM_PUSH(reg) "pushl %%e" reg " \n\t" 0051 #define ASM_XOR_REG(reg1, reg2) "xorl %%e" reg1 ", %%e" reg2 " \n\t" 0052 #define ASM_XOR_VAR(var, reg) "xorl " var ", %%e" reg " \n\t" 0053 #define ASM_CMP_REG(reg1, reg2) "cmpl %%e" reg1 ", %%e" reg2 " \n\t" 0054 #define ASM_MOV_REG(reg1, reg2) "movl %%e" reg1 ", %%e" reg2 " \n\t" 0055 #define ASM_MOV_VAR(var, reg) "movl " var ", %%e" reg " \n\t" 0056 #elif defined(__x86_64__) 0057 #define ASM_REG(reg) "%r" reg 0058 #define ASM_POP(reg) "popq %%r" reg " \n\t" 0059 #define ASM_PUSH(reg) "pushq %%r" reg " \n\t" 0060 #define ASM_XOR_REG(reg1, reg2) "xorq %%r" reg1 ", %%r" reg2 " \n\t" 0061 #define ASM_XOR_VAR(var, reg) "xorq " var ", %%r" reg " \n\t" 0062 #define ASM_CMP_REG(reg1, reg2) "cmpq %%r" reg1 ", %%r" reg2 " \n\t" 0063 #define ASM_MOV_REG(reg1, reg2) "movq %%r" reg1 ", %%r" reg2 " \n\t" 0064 #define ASM_MOV_VAR(var, reg) "movq " var ", %%r" reg " \n\t" 0065 #endif 0066 #endif 0067 0068 #ifdef __PPC__ 0069 static sigjmp_buf jmpbuf; 0070 static sig_atomic_t canjump = 0; 0071 0072 static void sigill_handler(int sig) 0073 { 0074 if (!canjump) { 0075 signal(sig, SIG_DFL); 0076 raise(sig); 0077 } 0078 canjump = 0; 0079 siglongjmp(jmpbuf, 1); 0080 } 0081 #endif 0082 0083 Solid::Processor::InstructionSets cpuFeatures() 0084 { 0085 volatile unsigned int features = 0; 0086 0087 #if defined( HAVE_GNU_INLINE_ASM ) 0088 #if defined( __i386__ ) || defined( __x86_64__ ) 0089 bool haveCPUID = false; 0090 unsigned int result = 0; 0091 unsigned int result2 = 0; 0092 0093 // First check if the CPU supports the CPUID instruction 0094 __asm__ __volatile__( 0095 // Try to toggle the CPUID bit in the EFLAGS register 0096 "pushf \n\t" // Push the EFLAGS register onto the stack 0097 ASM_POP("cx") // Pop the value into ECX 0098 ASM_MOV_REG("cx", "dx") // Copy ECX to EDX 0099 ASM_XOR_VAR("$0x00200000", "cx") // Toggle bit 21 (CPUID) in ECX 0100 ASM_PUSH("cx") // Push the modified value onto the stack 0101 "popf \n\t" // Pop it back into EFLAGS 0102 0103 // Check if the CPUID bit was successfully toggled 0104 "pushf \n\t" // Push EFLAGS back onto the stack 0105 ASM_POP("cx") // Pop the value into ECX 0106 ASM_XOR_REG("ax", "ax") // Zero out the EAX register 0107 ASM_CMP_REG("cx", "dx") // Compare ECX with EDX 0108 "je .Lno_cpuid_support%= \n\t" // Jump if they're identical 0109 ASM_MOV_VAR("$1", "ax") // Set EAX to true 0110 ".Lno_cpuid_support%=: \n\t" 0111 : "=a"(haveCPUID) : : ASM_REG("cx"), ASM_REG("dx")); 0112 0113 // If we don't have CPUID we won't have the other extensions either 0114 if (haveCPUID) { 0115 // Execute CPUID with the feature request bit set 0116 __asm__ __volatile__( 0117 ASM_PUSH("bx") // Save EBX 0118 ASM_MOV_VAR("$1", "ax") // Set EAX to 1 (features request) 0119 "cpuid \n\t" // Call CPUID 0120 ASM_POP("bx") // Restore EBX 0121 : "=d"(result), "=c"(result2) : : ASM_REG("ax")); 0122 0123 features = result & 0x06800000; //copy the mmx and sse & sse2 bits to features 0124 features |= result2 & 0x00180101; //copy the ssse3, sse3 and sse4.1, sse4.2 bits to features 0125 0126 __asm__ __volatile__( 0127 ASM_PUSH("bx") 0128 ASM_PUSH("dx") 0129 ASM_MOV_VAR("$0x80000000", "ax") 0130 ASM_MOV_VAR("$0x80000000", "dx") 0131 "cpuid \n\t" 0132 ASM_CMP_REG("dx", "ax") 0133 "jbe .Lno_extended%= \n\t" 0134 ASM_MOV_VAR("$0x80000001", "ax") 0135 "cpuid \n\t" 0136 ".Lno_extended%=: \n\t" 0137 ASM_POP("dx") 0138 ASM_POP("bx") // Restore EBX 0139 : "=d"(result) : : ASM_REG("ax"), ASM_REG("cx")); 0140 0141 if (result & 0x80000000) { 0142 features |= 0x80000000; 0143 } 0144 0145 #if HAVE_X86_SSE 0146 // Test bit 25 (SSE support) 0147 if (features & 0x02000000) { 0148 // OS support test for SSE. 0149 // Install our own sighandler for SIGILL. 0150 kde_sighandler_t oldhandler = std::signal(SIGILL, sighandler); 0151 0152 // Try executing an SSE insn to see if we get a SIGILL 0153 if (setjmp(env)) { 0154 features &= ~0x06080001; // The OS support test failed 0155 } else { 0156 __asm__ __volatile__("xorps %xmm0, %xmm0"); 0157 } 0158 0159 // Restore the default sighandler 0160 std::signal(SIGILL, oldhandler); 0161 0162 // Note: The OS requirements for SSE2 are the same as for SSE 0163 // so we don't have to do any additional tests for that. 0164 } 0165 #endif // HAVE_X86_SSE 0166 } 0167 #elif defined __PPC__ && HAVE_PPC_ALTIVEC 0168 signal(SIGILL, sigill_handler); 0169 if (sigsetjmp(jmpbuf, 1)) { 0170 signal(SIGILL, SIG_DFL); 0171 } else { 0172 canjump = 1; 0173 __asm__ __volatile__("mtspr 256, %0\n\t" 0174 "vand %%v0, %%v0, %%v0" 0175 : /* none */ 0176 : "r"(-1)); 0177 signal(SIGILL, SIG_DFL); 0178 features = 0x2; 0179 } 0180 #endif // __i386__ || __x86_64__ 0181 #elif defined(_MSC_VER) 0182 int array[4], ft = 1; 0183 __cpuid(array, ft); 0184 0185 features = array[3] & 0x06800000; //copy the mmx and sse & sse2 bits to features 0186 features |= array[2] & 0x00180101; //copy the ssse3, sse3 and sse4.1, sse4.2 bits to features 0187 0188 if (array[3] & 0x80000000) { 0189 features |= 0x80000000; 0190 } 0191 #endif //HAVE_GNU_INLINE_ASM 0192 Solid::Processor::InstructionSets featureflags; 0193 0194 if (features & 0x80000000) { 0195 featureflags |= Solid::Processor::Amd3DNow; 0196 } 0197 if (features & 0x00800000) { 0198 featureflags |= Solid::Processor::IntelMmx; 0199 } 0200 if (features & 0x02000000) { 0201 featureflags |= Solid::Processor::IntelSse; 0202 } 0203 if (features & 0x04000000) { 0204 featureflags |= Solid::Processor::IntelSse2; 0205 } 0206 if (features & 0x00000001) { 0207 featureflags |= Solid::Processor::IntelSse3; 0208 } 0209 if (features & 0x00000100) { 0210 featureflags |= Solid::Processor::IntelSsse3; 0211 } 0212 if (features & 0x00080000) { 0213 featureflags |= Solid::Processor::IntelSse41; 0214 } 0215 if (features & 0x00100000) { 0216 featureflags |= Solid::Processor::IntelSse42; 0217 } 0218 0219 if (features & 0x2) { 0220 featureflags |= Solid::Processor::AltiVec; 0221 } 0222 0223 return featureflags; 0224 } 0225 0226 } 0227 } 0228 }