cpu-feature: Support Via Padlock security features
[strongswan.git] / src / libstrongswan / utils / cpu_feature.c
1 /*
2 * Copyright (C) 2015 Martin Willi
3 * Copyright (C) 2015 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "cpu_feature.h"
17
18 #if defined __i386__ || defined(__x86_64__)
19
20 typedef enum {
21 /* Generic CPUID(1) flags */
22 CPUID1_EDX_MMX = (1 << 23),
23 CPUID1_EDX_SSE = (1 << 25),
24 CPUID1_EDX_SSE2 = (1 << 26),
25 CPUID1_ECX_SSE3 = (1 << 0),
26 CPUID1_ECX_PCLMULQDQ = (1 << 1),
27 CPUID1_ECX_SSSE3 = (1 << 9),
28 CPUID1_ECX_SSE41 = (1 << 19),
29 CPUID1_ECX_SSE42 = (1 << 20),
30 CPUID1_ECX_AESNI = (1 << 25),
31 CPUID1_ECX_AVX = (1 << 28),
32 CPUID1_ECX_RDRAND = (1 << 30),
33
34 /* For CentaurHauls cpuid(0xC0000001) */
35 CPUIDC1_EDX_RNG_AVAILABLE = (1 << 2),
36 CPUIDC1_EDX_RNG_ENABLED = (1 << 3),
37 CPUIDC1_EDX_ACE_AVAILABLE = (1 << 6),
38 CPUIDC1_EDX_ACE_ENABLED = (1 << 7),
39 CPUIDC1_EDX_ACE2_AVAILABLE = (1 << 8),
40 CPUIDC1_EDX_ACE2_ENABLED = (1 << 9),
41 CPUIDC1_EDX_PHE_AVAILABLE = (1 << 10),
42 CPUIDC1_EDX_PHE_ENABLED = (1 << 11),
43 CPUIDC1_EDX_PMM_AVAILABLE = (1 << 12),
44 CPUIDC1_EDX_PMM_ENABLED = (1 << 13),
45 } cpuid_flag_t;
46
47 /**
48 * Get cpuid for info, return eax, ebx, ecx and edx.
49 * -fPIC requires to save ebx on IA-32.
50 */
51 static void cpuid(u_int op, u_int *a, u_int *b, u_int *c, u_int *d)
52 {
53 #ifdef __x86_64__
54 asm("cpuid" : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d) : "a" (op));
55 #else /* __i386__ */
56 asm("pushl %%ebx;"
57 "cpuid;"
58 "movl %%ebx, %1;"
59 "popl %%ebx;"
60 : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d) : "a" (op));
61 #endif /* __x86_64__ / __i386__*/
62 }
63
64 /**
65 * Return feature if flag in reg, flag-to-feature
66 */
67 static inline cpu_feature_t f2f(u_int reg, cpuid_flag_t flag, cpu_feature_t f)
68 {
69 if (reg & flag)
70 {
71 return f;
72 }
73 return 0;
74 }
75
76 /**
77 * Get features for a Via "CentaurHauls" CPU
78 */
79 static cpu_feature_t get_via_features()
80 {
81 cpu_feature_t f = 0;
82 u_int a, b, c, d;
83
84 cpuid(0xc0000001, &a, &b, &c, &d);
85
86 f |= f2f(d, CPUIDC1_EDX_RNG_AVAILABLE, CPU_FEATURE_PADLOCK_RNG_AVAILABLE);
87 f |= f2f(d, CPUIDC1_EDX_RNG_ENABLED, CPU_FEATURE_PADLOCK_RNG_ENABLED);
88 f |= f2f(d, CPUIDC1_EDX_ACE_AVAILABLE, CPU_FEATURE_PADLOCK_ACE_AVAILABLE);
89 f |= f2f(d, CPUIDC1_EDX_ACE_ENABLED, CPU_FEATURE_PADLOCK_ACE_ENABLED);
90 f |= f2f(d, CPUIDC1_EDX_ACE2_AVAILABLE, CPU_FEATURE_PADLOCK_ACE2_AVAILABLE);
91 f |= f2f(d, CPUIDC1_EDX_ACE2_ENABLED, CPU_FEATURE_PADLOCK_ACE2_ENABLED);
92 f |= f2f(d, CPUIDC1_EDX_PHE_AVAILABLE, CPU_FEATURE_PADLOCK_PHE_AVAILABLE);
93 f |= f2f(d, CPUIDC1_EDX_PHE_ENABLED, CPU_FEATURE_PADLOCK_PHE_ENABLED);
94 f |= f2f(d, CPUIDC1_EDX_PMM_AVAILABLE, CPU_FEATURE_PADLOCK_PMM_AVAILABLE);
95 f |= f2f(d, CPUIDC1_EDX_PMM_ENABLED, CPU_FEATURE_PADLOCK_PMM_ENABLED);
96
97 return f;
98 }
99
100 /**
101 * See header.
102 */
103 cpu_feature_t cpu_feature_get_all()
104 {
105 char vendor[3 * sizeof(u_int32_t) + 1];
106 cpu_feature_t f = 0;
107 u_int a, b, c, d;
108
109 cpuid(0, &a, &b, &c, &d);
110 /* VendorID string is in b-d-c (yes, in this order) */
111 snprintf(vendor, sizeof(vendor), "%.4s%.4s%.4s", &b, &d, &c);
112
113 cpuid(1, &a, &b, &c, &d);
114
115 /* check common x86 features for CPUID(1) */
116 f |= f2f(d, CPUID1_EDX_MMX, CPU_FEATURE_MMX);
117 f |= f2f(d, CPUID1_EDX_SSE, CPU_FEATURE_SSE);
118 f |= f2f(d, CPUID1_EDX_SSE2, CPU_FEATURE_SSE2);
119 f |= f2f(c, CPUID1_ECX_SSE3, CPU_FEATURE_SSE3);
120 f |= f2f(c, CPUID1_ECX_PCLMULQDQ, CPU_FEATURE_PCLMULQDQ);
121 f |= f2f(c, CPUID1_ECX_SSSE3, CPU_FEATURE_SSSE3);
122 f |= f2f(c, CPUID1_ECX_SSE41, CPU_FEATURE_SSE41);
123 f |= f2f(c, CPUID1_ECX_SSE42, CPU_FEATURE_SSE42);
124 f |= f2f(c, CPUID1_ECX_AESNI, CPU_FEATURE_AESNI);
125 f |= f2f(c, CPUID1_ECX_AVX, CPU_FEATURE_AVX);
126 f |= f2f(c, CPUID1_ECX_RDRAND, CPU_FEATURE_RDRAND);
127
128 if (streq(vendor, "CentaurHauls"))
129 {
130 cpuid(0xc0000000, &a, &b, &c, &d);
131 /* check Centaur Extended Feature Flags */
132 if (a >= 0xc0000001)
133 {
134 f |= get_via_features();
135 }
136 }
137 return f;
138 }
139
140 #else /* !x86 */
141
142 /**
143 * See header.
144 */
145 cpu_feature_t cpu_feature_get_all()
146 {
147 return 0;
148 }
149
150 #endif
151
152 /**
153 * See header.
154 */
155 bool cpu_feature_available(cpu_feature_t feature)
156 {
157 return (cpu_feature_get_all() & feature) == feature;
158 }