X-Git-Url: http://git.silc.fi/gitweb/?p=runtime.git;a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilccpuid.c;fp=lib%2Fsilcutil%2Fsilccpuid.c;h=d969c5e2ade20d36685d0ae88cb6ac9d5280bd42;hp=0000000000000000000000000000000000000000;hb=5c254480e0e134335eb3a57d15884d126a789129;hpb=50c7d0d8c918d275751c9263cb64b6a3e847db67 diff --git a/lib/silcutil/silccpuid.c b/lib/silcutil/silccpuid.c new file mode 100644 index 00000000..d969c5e2 --- /dev/null +++ b/lib/silcutil/silccpuid.c @@ -0,0 +1,123 @@ +/* + + silccpuid.c + + Author: Pekka Riikonen + + Copyright (C) 2008 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include + +#if defined(SILC_I486) || defined(SILC_X86_64) +static void silc_cpuid(SilcUInt32 level, SilcUInt32 *ecx, SilcUInt32 *edx) +{ + /* This works on modern CPUs. Probably fails on some ancient CPUs. */ + asm volatile ("xorl %%ecx, %%ecx \n" + "xorl %%edx, %%edx \n" + "movl %2, %%eax \n" + "cpuid \n" + "movl %%edx, %0 \n" + "movl %%ecx, %1 \n" + : "=m" (*edx), "=m" (*ecx) + : "r" (level) + : "ebx", "eax", "ecx", "edx"); + + SILC_LOG_DEBUG(("CPUID 0x%08x: ecx=0x%08x, edx=0x%08x", level, *ecx, *edx)); +} +#endif /* SILC_I486 || SILC_X86_64 */ + +SilcCPUIdFeatures silc_cpuid_features(void) +{ + SilcCPUIdFeatures id = SILC_CPUID_UNKNOWN; +#if defined(SILC_I486) || defined(SILC_X86_64) + SilcUInt32 ecx = 0, edx = 0; + + /* Basic level */ + silc_cpuid(1, &ecx, &edx); + if (!edx) + return SILC_CPUID_UNKNOWN; + + SILC_LOG_DEBUG(("386")); + id = SILC_CPUID_386; + + if (edx & (1 << 23)) { + SILC_LOG_DEBUG(("MMX")); + id |= SILC_CPUID_MMX; + } + + if (edx & (1 << 15)) { + SILC_LOG_DEBUG(("CMOV")); + id |= SILC_CPUID_CMOV; + } + + if (edx & (1 << 25)) { + SILC_LOG_DEBUG(("SSE")); + id |= SILC_CPUID_SSE; + } + + if (edx & (1 << 26)) { + SILC_LOG_DEBUG(("SSE2")); + id |= SILC_CPUID_SSE2; + } + + if (ecx & (1 << 0)) { + SILC_LOG_DEBUG(("SSE3")); + id |= SILC_CPUID_SSE3; + } + + if (ecx & (1 << 9)) { + SILC_LOG_DEBUG(("SSSE3")); + id |= SILC_CPUID_SSSE3; + } + + if (ecx & (1 << 19)) { + SILC_LOG_DEBUG(("SSE4.1")); + id |= SILC_CPUID_SSE41; + } + + if (ecx & (1 << 20)) { + SILC_LOG_DEBUG(("SSE4.2")); + id |= SILC_CPUID_SSE41; + } + + if (ecx & (1 << 28)) { + SILC_LOG_DEBUG(("AVX")); + id |= SILC_CPUID_AVX; + } + + if (ecx & (1 << 25)) { + SILC_LOG_DEBUG(("AES")); + id |= SILC_CPUID_AES; + } + + /* Extended level */ + ecx = edx = 0; + silc_cpuid(0x80000001, &ecx, &edx); + if (!ecx) + goto out; + + if (ecx & (1 << 6)) { + SILC_LOG_DEBUG(("SSE4a")); + id |= SILC_CPUID_SSE4A; + } + + if (ecx & (1 << 25)) { + SILC_LOG_DEBUG(("SSE5")); + id |= SILC_CPUID_SSE5; + } + + out: +#endif /* SILC_I486 || SILC_X86_64 */ + return id; +}