Added SILC CPUID API
[runtime.git] / lib / silcutil / silccpuid.c
1 /*
2
3   silccpuid.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2008 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include <silcruntime.h>
21
22 #if defined(SILC_I486) || defined(SILC_X86_64)
23 static void silc_cpuid(SilcUInt32 level, SilcUInt32 *ecx, SilcUInt32 *edx)
24 {
25   /* This works on modern CPUs.  Probably fails on some ancient CPUs. */
26   asm volatile ("xorl %%ecx, %%ecx   \n"
27                 "xorl %%edx, %%edx   \n"
28                 "movl %2, %%eax      \n"
29                 "cpuid               \n"
30                 "movl %%edx, %0      \n"
31                 "movl %%ecx, %1      \n"
32                 : "=m" (*edx), "=m" (*ecx)
33                 : "r" (level)
34                 : "ebx", "eax", "ecx", "edx");
35
36   SILC_LOG_DEBUG(("CPUID 0x%08x: ecx=0x%08x, edx=0x%08x", level, *ecx, *edx));
37 }
38 #endif /* SILC_I486 || SILC_X86_64 */
39
40 SilcCPUIdFeatures silc_cpuid_features(void)
41 {
42   SilcCPUIdFeatures id = SILC_CPUID_UNKNOWN;
43 #if defined(SILC_I486) || defined(SILC_X86_64)
44   SilcUInt32 ecx = 0, edx = 0;
45
46   /* Basic level */
47   silc_cpuid(1, &ecx, &edx);
48   if (!edx)
49     return SILC_CPUID_UNKNOWN;
50
51   SILC_LOG_DEBUG(("386"));
52   id = SILC_CPUID_386;
53
54   if (edx & (1 << 23)) {
55     SILC_LOG_DEBUG(("MMX"));
56     id |= SILC_CPUID_MMX;
57   }
58
59   if (edx & (1 << 15)) {
60     SILC_LOG_DEBUG(("CMOV"));
61     id |= SILC_CPUID_CMOV;
62   }
63
64   if (edx & (1 << 25)) {
65     SILC_LOG_DEBUG(("SSE"));
66     id |= SILC_CPUID_SSE;
67   }
68
69   if (edx & (1 << 26)) {
70     SILC_LOG_DEBUG(("SSE2"));
71     id |= SILC_CPUID_SSE2;
72   }
73
74   if (ecx & (1 << 0)) {
75     SILC_LOG_DEBUG(("SSE3"));
76     id |= SILC_CPUID_SSE3;
77   }
78
79   if (ecx & (1 << 9)) {
80     SILC_LOG_DEBUG(("SSSE3"));
81     id |= SILC_CPUID_SSSE3;
82   }
83
84   if (ecx & (1 << 19)) {
85     SILC_LOG_DEBUG(("SSE4.1"));
86     id |= SILC_CPUID_SSE41;
87   }
88
89   if (ecx & (1 << 20)) {
90     SILC_LOG_DEBUG(("SSE4.2"));
91     id |= SILC_CPUID_SSE41;
92   }
93
94   if (ecx & (1 << 28)) {
95     SILC_LOG_DEBUG(("AVX"));
96     id |= SILC_CPUID_AVX;
97   }
98
99   if (ecx & (1 << 25)) {
100     SILC_LOG_DEBUG(("AES"));
101     id |= SILC_CPUID_AES;
102   }
103
104   /* Extended level */
105   ecx = edx = 0;
106   silc_cpuid(0x80000001, &ecx, &edx);
107   if (!ecx)
108     goto out;
109
110   if (ecx & (1 << 6)) {
111     SILC_LOG_DEBUG(("SSE4a"));
112     id |= SILC_CPUID_SSE4A;
113   }
114
115   if (ecx & (1 << 25)) {
116     SILC_LOG_DEBUG(("SSE5"));
117     id |= SILC_CPUID_SSE5;
118   }
119
120  out:
121 #endif /* SILC_I486 || SILC_X86_64 */
122   return id;
123 }