Added SILC CPUID API
authorPekka Riikonen <priikone@silcnet.org>
Sat, 1 Nov 2008 09:29:52 +0000 (11:29 +0200)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 1 Nov 2008 09:29:52 +0000 (11:29 +0200)
The API can be used to determine the features of the x86 and x86-64 CPUs
on the fly.

lib/silcutil/Makefile.ad
lib/silcutil/silccpuid.c [new file with mode: 0644]
lib/silcutil/silccpuid.h [new file with mode: 0644]
lib/silcutil/silcruntime.h.in
lib/silcutil/silctypes.h
lib/silcutil/tests/Makefile.am
lib/silcutil/tests/test_silccpuid.c [new file with mode: 0644]
scripts/release

index 9ddeb19e79e0f68788a592405962281bb6ac545a..1fd4496279ee7d4ccf7499d8ffd96553a08e4905 100644 (file)
@@ -71,7 +71,8 @@ libsilcutil_la_SOURCES = \
        silcbufferstream.c \
        silclocalnetstream.c \
        silcxml.c       \
-       silcavltree.c
+       silcavltree.c   \
+       silccpuid.c
 
 include_HEADERS =      \
        $(SILC_DIST_HEADER) \
@@ -131,7 +132,8 @@ include_HEADERS =   \
        silclocalnetstream.h \
        silcxml.h       \
        silctree.h      \
-       silctree_i.h
+       silctree_i.h    \
+       silccpuid.h
 
 SILC_EXTRA_DIST =
 
diff --git a/lib/silcutil/silccpuid.c b/lib/silcutil/silccpuid.c
new file mode 100644 (file)
index 0000000..d969c5e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+
+  silccpuid.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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 <silcruntime.h>
+
+#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;
+}
diff --git a/lib/silcutil/silccpuid.h b/lib/silcutil/silccpuid.h
new file mode 100644 (file)
index 0000000..b5114d3
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+
+  silccpuid.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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.
+
+*/
+
+#ifndef SILCCPUID_H
+#define SILCCPUID_H
+
+/****d* silcutil/SilcCPUIdFeatures
+ *
+ * NAME
+ *
+ *    typedef enum { ... } SilcCPUIdFeatures;
+ *
+ * DESCRIPTION
+ *
+ *    CPU features.  Indicates which instruction sets the CPU supports.
+ *
+ */
+typedef enum {
+  SILC_CPUID_UNKNOWN     = 0x00000000,           /* 386 only */
+  SILC_CPUID_386         = 0x00000002,           /* 386 */
+  SILC_CPUID_MMX         = 0x00000004,          /* MMX */
+  SILC_CPUID_CMOV        = 0x00000008,          /* CMOV, FCOMI */
+  SILC_CPUID_SSE         = 0x00000010,          /* SSE */
+  SILC_CPUID_SSE2        = 0x00000020,          /* SSE2 */
+  SILC_CPUID_SSE3        = 0x00000040,          /* SSE3 */
+  SILC_CPUID_SSSE3       = 0x00000080,          /* SSSE3 */
+  SILC_CPUID_SSE41       = 0x00000100,          /* SSE4.1 */
+  SILC_CPUID_SSE42       = 0x00000200,          /* SSE4.2 */
+  SILC_CPUID_SSE4A       = 0x00000400,          /* SSE4a */
+  SILC_CPUID_SSE5        = 0x00000800,          /* SSE5 */
+  SILC_CPUID_AVX         = 0x00001000,          /* AVX */
+  SILC_CPUID_AES         = 0x00002000,          /* AES */
+} SilcCPUIdFeatures;
+/***/
+
+/****f* silcutil/silc_cpuid_features
+ *
+ * SYNOPSIS
+ *
+ *    SilcCPUIdFeatures silc_cpuid_features(void);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the CPU instruction set features.  The ID can be used to
+ *    determine what features the CPU supports.  The returned value is a
+ *    bitmask of supported features.
+ *
+ * NOTES
+ *
+ *    This function should not be called at a code path where speed is
+ *    critical.  It is recommended to call this once and later use the
+ *    returned value to determine features.
+ *
+ *    This function works only on x86 or x86-64 CPUs.
+ *
+ ***/
+SilcCPUIdFeatures silc_cpuid_features(void);
+
+#endif /* SILCCPUID_H */
index 6d20103c6d962a7b971ae9ccfaed2150cf252a8d..1a8e3e7e32adde1d20d36618472452f796c69679 100644 (file)
@@ -200,6 +200,7 @@ extern "C" {
 
 /* SILC Runtime Toolkit includes */
 #include <silctypes.h>
+#include <silccpuid.h>
 #include <silcerrno.h>
 #include <silcbitops.h>
 #include <silcmutex.h>
index 5d768d819ab70828b844996265ef97ce2befddc3..802f81138e35975fd36ba86ceac638169d5b2002 100644 (file)
@@ -163,14 +163,14 @@ typedef signed short SilcInt16;
  *
  * SOURCE
  */
-#if SILC_SIZEOF_LONG == 4
-typedef unsigned long SilcUInt32;
-typedef signed long SilcInt32;
-#else
 #if SILC_SIZEOF_INT == 4
 typedef unsigned int SilcUInt32;
 typedef signed int SilcInt32;
 #else
+#if SILC_SIZEOF_LONG == 4
+typedef unsigned long SilcUInt32;
+typedef signed long SilcInt32;
+#else
 #if SILC_SIZEOF_LONG_LONG >= 4
 #ifndef WIN32
 typedef unsigned long long SilcUInt32;
@@ -1325,4 +1325,11 @@ void silc_prefetch_block(void *addr,
 #undef SILC_PREFETCH_ASM
 }
 
+typedef char __check_size1[sizeof(SilcInt8)   ==       1 ? 1 : -1];
+typedef char __check_size2[sizeof(SilcUInt8)  ==       1 ? 1 : -1];
+typedef char __check_size3[sizeof(SilcInt16)  ==       2 ? 1 : -1];
+typedef char __check_size4[sizeof(SilcUInt16) ==       2 ? 1 : -1];
+typedef char __check_size5[sizeof(SilcInt32)  ==       4 ? 1 : -1];
+typedef char __check_size6[sizeof(SilcUInt32) ==       4 ? 1 : -1];
+
 #endif /* SILCTYPES_H */
index 77aa4b7a693506a61c4bc5a081062d7a8039a546..b7519c61feca9e9178c90ffef7a24ec7138b9f2e 100644 (file)
@@ -25,7 +25,7 @@ check_PROGRAMS = \
        test_silcdll test_silcenv test_silctimer test_silcbitops \
        test_silcregex test_silcbuffmt test_silcdir test_silcthreadqueue \
        test_silcrand test_silcglobal test_silcbufferstream test_silcxml \
-       test_silclocalnetstream test_silctree
+       test_silclocalnetstream test_silctree test_silccpuid
 
 TESTS = test_silcstrutil test_silcstringprep test_silchashtable \
        test_silclist test_silcfsm test_silcasync test_silcschedule \
@@ -34,7 +34,7 @@ TESTS = test_silcstrutil test_silcstringprep test_silchashtable \
        test_silcdll test_silcenv test_silctimer test_silcbitops \
        test_silcregex test_silcbuffmt test_silcdir test_silcthreadqueue \
        test_silcrand test_silcglobal test_silcbufferstream \
-       test_silclocalnetstream test_silctree
+       test_silclocalnetstream test_silctree test_silccpuid
 
 LIBS = $(SILC_COMMON_LIBS)
 LDADD = -L.. -L../.. -lsrt
diff --git a/lib/silcutil/tests/test_silccpuid.c b/lib/silcutil/tests/test_silccpuid.c
new file mode 100644 (file)
index 0000000..8e4da50
--- /dev/null
@@ -0,0 +1,26 @@
+/* CPUID tests */
+
+#include "silcruntime.h"
+
+int main(int argc, char **argv)
+{
+  SilcBool success = FALSE;
+  SilcCPUIdFeatures id;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_log_debug(TRUE);
+    silc_log_quick(TRUE);
+    silc_log_debug_hexdump(TRUE);
+    silc_log_set_debug_string("*cpu*");
+  }
+
+  id = silc_cpuid_features();
+
+  success = TRUE;
+
+// err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  return !success;
+}
index b5ab3fb38761a28ac27a29f4adf3e01b32a8e87b..55e592e2ec4f157c5d207250048eb745c6f92dc3 100644 (file)
@@ -2,7 +2,7 @@
 
 last="$1"
 new="$2"
-git tag $new
-git log --no-merges $new ^$last > ChangeLog
+git tag -a -m "Release $new" $new
+git log --no-merges $new ^$last >> ChangeLog
 echo "" >> ChangeLog
 git diff --stat --summary -M $last $new >> ChangeLog