cpu-feature: Add a common class to query available CPU features
authorMartin Willi <martin@revosec.ch>
Thu, 2 Apr 2015 12:02:57 +0000 (14:02 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 13 Apr 2015 13:31:58 +0000 (15:31 +0200)
Currently supported is x86/x64 via cpuid() for some common features.

src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/utils/cpu_feature.c [new file with mode: 0644]
src/libstrongswan/utils/cpu_feature.h [new file with mode: 0644]

index d9cc08a..b137b73 100644 (file)
@@ -36,7 +36,7 @@ pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
 selectors/traffic_selector.c settings/settings.c settings/settings_types.c \
-settings/settings_parser.c settings/settings_lexer.c \
+settings/settings_parser.c settings/settings_lexer.c utils/cpu_feature.c \
 utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
 utils/parser_helper.c utils/test.c utils/process.c utils/utils/strerror.c
index 2521b3e..f738072 100644 (file)
@@ -34,7 +34,7 @@ pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c
 processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \
 processing/watcher.c resolver/resolver_manager.c resolver/rr_set.c \
 selectors/traffic_selector.c settings/settings.c settings/settings_types.c \
-settings/settings_parser.y settings/settings_lexer.l \
+settings/settings_parser.y settings/settings_lexer.l utils/cpu_feature.c \
 utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
 utils/parser_helper.c utils/test.c utils/process.c utils/utils/strerror.c
@@ -103,7 +103,7 @@ threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h
 threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \
 utils/utils.h utils/chunk.h utils/debug.h utils/enum.h utils/identification.h \
 utils/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \
-utils/leak_detective.h utils/printf_hook/printf_hook.h \
+utils/cpu_feature.h utils/leak_detective.h utils/printf_hook/printf_hook.h \
 utils/printf_hook/printf_hook_vstr.h utils/printf_hook/printf_hook_builtin.h \
 utils/parser_helper.h utils/test.h utils/integrity_checker.h utils/process.h \
 utils/utils/strerror.h utils/compat/windows.h utils/compat/apple.h
diff --git a/src/libstrongswan/utils/cpu_feature.c b/src/libstrongswan/utils/cpu_feature.c
new file mode 100644 (file)
index 0000000..b88cf2f
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 "cpu_feature.h"
+
+#if defined __i386__ || defined(__x86_64__)
+
+typedef enum {
+       /* Generic CPUID(1) flags */
+       CPUID1_EDX_MMX =                                (1 << 23),
+       CPUID1_EDX_SSE =                                (1 << 25),
+       CPUID1_EDX_SSE2 =                               (1 << 26),
+       CPUID1_ECX_SSE3 =                               (1 <<  0),
+       CPUID1_ECX_PCLMULQDQ =                  (1 <<  1),
+       CPUID1_ECX_SSSE3 =                              (1 <<  9),
+       CPUID1_ECX_SSE41 =                              (1 << 19),
+       CPUID1_ECX_SSE42 =                              (1 << 20),
+       CPUID1_ECX_AESNI =                              (1 << 25),
+       CPUID1_ECX_AVX =                                (1 << 28),
+       CPUID1_ECX_RDRAND =                             (1 << 30),
+} cpuid_flag_t;
+
+/**
+ * Get cpuid for info, return eax, ebx, ecx and edx.
+ * -fPIC requires to save ebx on IA-32.
+ */
+static void cpuid(u_int op, u_int *a, u_int *b, u_int *c, u_int *d)
+{
+#ifdef __x86_64__
+       asm("cpuid" : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d) : "a" (op));
+#else /* __i386__ */
+       asm("pushl %%ebx;"
+               "cpuid;"
+               "movl %%ebx, %1;"
+               "popl %%ebx;"
+               : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d) : "a" (op));
+#endif /* __x86_64__ / __i386__*/
+}
+
+/**
+ * Return feature if flag in reg, flag-to-feature
+ */
+static inline cpu_feature_t f2f(u_int reg, cpuid_flag_t flag, cpu_feature_t f)
+{
+       if (reg & flag)
+       {
+               return f;
+       }
+       return 0;
+}
+
+/**
+ * See header.
+ */
+cpu_feature_t cpu_feature_get_all()
+{
+       char vendor[3 * sizeof(u_int32_t) + 1];
+       cpu_feature_t f = 0;
+       u_int a, b, c, d;
+
+       cpuid(0, &a, &b, &c, &d);
+       /* VendorID string is in b-d-c (yes, in this order) */
+       snprintf(vendor, sizeof(vendor), "%.4s%.4s%.4s", &b, &d, &c);
+
+       cpuid(1, &a, &b, &c, &d);
+
+       /* check common x86 features for CPUID(1) */
+       f |= f2f(d, CPUID1_EDX_MMX, CPU_FEATURE_MMX);
+       f |= f2f(d, CPUID1_EDX_SSE, CPU_FEATURE_SSE);
+       f |= f2f(d, CPUID1_EDX_SSE2, CPU_FEATURE_SSE2);
+       f |= f2f(c, CPUID1_ECX_SSE3, CPU_FEATURE_SSE3);
+       f |= f2f(c, CPUID1_ECX_PCLMULQDQ, CPU_FEATURE_PCLMULQDQ);
+       f |= f2f(c, CPUID1_ECX_SSSE3, CPU_FEATURE_SSSE3);
+       f |= f2f(c, CPUID1_ECX_SSE41, CPU_FEATURE_SSE41);
+       f |= f2f(c, CPUID1_ECX_SSE42, CPU_FEATURE_SSE42);
+       f |= f2f(c, CPUID1_ECX_AESNI, CPU_FEATURE_AESNI);
+       f |= f2f(c, CPUID1_ECX_AVX, CPU_FEATURE_AVX);
+       f |= f2f(c, CPUID1_ECX_RDRAND, CPU_FEATURE_RDRAND);
+
+       return f;
+}
+
+#else /* !x86 */
+
+/**
+ * See header.
+ */
+cpu_feature_t cpu_feature_get_all()
+{
+       return 0;
+}
+
+#endif
+
+/**
+ * See header.
+ */
+bool cpu_feature_available(cpu_feature_t feature)
+{
+       return (cpu_feature_get_all() & feature) == feature;
+}
diff --git a/src/libstrongswan/utils/cpu_feature.h b/src/libstrongswan/utils/cpu_feature.h
new file mode 100644 (file)
index 0000000..d7300a3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 Martin Willi
+ * Copyright (C) 2015 revosec AG
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup cpu_feature cpu_feature
+ * @{ @ingroup utils
+ */
+
+#ifndef CPU_FEATURE_H_
+#define CPU_FEATURE_H_
+
+#include <library.h>
+
+typedef enum {
+       /** x86/x64 extensions */
+       CPU_FEATURE_MMX =                                                       (1 <<  0),
+       CPU_FEATURE_SSE =                                                       (1 <<  1),
+       CPU_FEATURE_SSE2 =                                                      (1 <<  2),
+       CPU_FEATURE_SSE3 =                                                      (1 <<  3),
+       CPU_FEATURE_SSSE3 =                                                     (1 <<  4),
+       CPU_FEATURE_SSE41 =                                                     (1 <<  5),
+       CPU_FEATURE_SSE42 =                                                     (1 <<  6),
+       CPU_FEATURE_AVX =                                                       (1 <<  7),
+       CPU_FEATURE_RDRAND =                                            (1 <<  8),
+       CPU_FEATURE_AESNI =                                                     (1 <<  9),
+       CPU_FEATURE_PCLMULQDQ =                                         (1 << 10),
+} cpu_feature_t;
+
+/**
+ * Get a bitmask for all supported CPU features
+ */
+cpu_feature_t cpu_feature_get_all();
+
+/**
+ * Check if a given set of CPU features is available.
+ */
+bool cpu_feature_available(cpu_feature_t feature);
+
+#endif /** CPU_FEATURE_H_ @}*/