Prepare for hardware feature detection on other platforms.
authorWerner Koch <wk@gnupg.org>
Fri, 21 Dec 2012 16:26:06 +0000 (17:26 +0100)
committerWerner Koch <wk@gnupg.org>
Fri, 21 Dec 2012 16:26:06 +0000 (17:26 +0100)
* configure.ac (GCRYPT_HWF_MODULES): New.
(HAVE_CPU_ARCH_X86, HAVE_CPU_ARCH_ALPHA, HAVE_CPU_ARCH_SPARC)
(HAVE_CPU_ARCH_MIPS, HAVE_CPU_ARCH_M68K, HAVE_CPU_ARCH_PPC)
(HAVE_CPU_ARCH_ARM): New AC_DEFINEs.
* mpi/config.links (mpi_cpu_arch): New.
* src/global.c (print_config): Print new tag "cpu-arch".
* src/Makefile.am (libgcrypt_la_SOURCES): Add hwf-common.h
(EXTRA_libgcrypt_la_SOURCES): New.
(gcrypt_hwf_modules): New.
(libgcrypt_la_DEPENDENCIES, libgcrypt_la_LIBADD): Add that one.
* src/hwfeatures.c: Factor most code out to ...
* src/hwf-x86.c: New file.
(detect_x86_gnuc): Return the feature vector.
(_gcry_hwf_detect_x86): New.
* src/hwf-common.h: New.
* src/hwfeatures.c (_gcry_detect_hw_features): Dispatch using
HAVE_CPU_ARCH_ macros.

Signed-off-by: Werner Koch <wk@gnupg.org>
configure.ac
mpi/config.links
src/Makefile.am
src/global.c
src/hwf-common.h [new file with mode: 0644]
src/hwf-x86.c [new file with mode: 0644]
src/hwfeatures.c

index 7d162a2..5e57868 100644 (file)
@@ -1,6 +1,7 @@
 # Configure.ac script for Libgcrypt
 # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006,
 #               2007, 2008, 2009, 2011 Free Software Foundation, Inc.
+# Copyright (C) 2012  g10 Code GmbH
 #
 # This file is part of Libgcrypt.
 #
@@ -958,6 +959,9 @@ fi
 #
 # Setup assembler stuff.
 #
+# Note that config.links also defines mpi_cpu_arch, which is required
+# later on.
+#
 GNUPG_SYS_SYMBOL_UNDERSCORE()
 AC_ARG_ENABLE(mpi-path,
               AC_HELP_STRING([--enable-mpi-path=EXTRA_PATH],
@@ -1269,6 +1273,38 @@ AC_DEFINE_UNQUOTED(LIBGCRYPT_DIGESTS, "$tmp",
                    [List of available digest algorithms])
 
 
+#
+# Define conditional sources depending on the used hardware platform.
+# Note that all possible modules must also be listed in
+# src/Makefile.am (EXTRA_libgcrypt_la_SOURCES).
+#
+GCRYPT_HWF_MODULES=
+case "$mpi_cpu_arch" in
+     x86)
+        AC_DEFINE(HAVE_CPU_ARCH_X86, 1,   [Defined for the x86 platforms])
+        GCRYPT_HWF_MODULES="hwf-x86.lo"
+        ;;
+     alpha)
+        AC_DEFINE(HAVE_CPU_ARCH_ALPHA, 1, [Defined for Alpha platforms])
+        ;;
+     sparc)
+        AC_DEFINE(HAVE_CPU_ARCH_SPARC, 1, [Defined for SPARC platforms])
+        ;;
+     mips)
+        AC_DEFINE(HAVE_CPU_ARCH_MIPS, 1,  [Defined for MIPS platforms])
+        ;;
+     m68k)
+        AC_DEFINE(HAVE_CPU_ARCH_M68K, 1,  [Defined for M68k platforms])
+        ;;
+     ppc)
+        AC_DEFINE(HAVE_CPU_ARCH_PPC, 1,   [Defined for PPC platforms])
+        ;;
+     arm)
+        AC_DEFINE(HAVE_CPU_ARCH_ARM, 1,   [Defined for ARM platforms])
+        ;;
+esac
+AC_SUBST([GCRYPT_HWF_MODULES])
+
 
 # Generate extended version information for W32.
 if test "$have_w32_system" = yes; then
@@ -1304,11 +1340,16 @@ tests/Makefile
 ])
 AC_OUTPUT
 
+
+detection_module="${GCRYPT_HWF_MODULES%.lo}"
+test -n "$detection_module" || detection_module="none"
+
 # Give some feedback
 echo "
         Libgcrypt v${VERSION} has been configured as follows:
 
         Platform:                  $PRINTABLE_OS_NAME ($host)
+        Hardware detection module: $detection_module
         Enabled cipher algorithms: $enabled_ciphers
         Enabled digest algorithms: $enabled_digests
         Enabled pubkey algorithms: $enabled_pubkey_ciphers
index 7e910ee..bcc6e3e 100644 (file)
@@ -1,5 +1,6 @@
 # config.links - helper for ../configure             -*- mode: sh -*-
 # Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+# Copyright (C) 2012  g10 Code GmbH
 #
 # This file is part of Libgcrypt.
 #
@@ -23,6 +24,7 @@
 
 mpi_sflags=
 mpi_extra_modules=
+mpi_cpu_arch=
 
 test -d ./mpi || mkdir ./mpi
 
@@ -44,6 +46,7 @@ case "${host}" in
     i[34567]86*-*-openbsd3.[0123]*)
        echo '/* No working assembler modules available */' >>./mpi/asm-syntax.h
        path=""
+       mpi_cpu_arch="x86"
        ;;
     i[3467]86*-*-openbsd*      | \
     i[3467]86*-*-freebsd*-elf  | \
@@ -54,6 +57,7 @@ case "${host}" in
        echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h     >>./mpi/asm-syntax.h
        path="i386"
+       mpi_cpu_arch="x86"
        ;;
     i586*-*-openbsd*         | \
     i586*-*-freebsd*-elf     | \
@@ -66,11 +70,13 @@ case "${host}" in
        echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h     >>./mpi/asm-syntax.h
        path="i586 i386"
+       mpi_cpu_arch="x86"
        ;;
     i[34]86*-*-bsdi4*)
        echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h   >>./mpi/asm-syntax.h
        path="i386"
+       mpi_cpu_arch="x86"
        ;;
     i[3467]86*-*-linuxaout*  | \
     i[3467]86*-*-linuxoldld* | \
@@ -79,6 +85,7 @@ case "${host}" in
        echo '#define X86_BROKEN_ALIGN' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h      >>./mpi/asm-syntax.h
        path="i386"
+        mpi_cpu_arch="x86"
        ;;
     i586*-*-linuxaout*  | \
     i586*-*-linuxoldld* | \
@@ -87,23 +94,27 @@ case "${host}" in
        echo '#define X86_BROKEN_ALIGN' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h      >>./mpi/asm-syntax.h
        path="i586 i386"
+        mpi_cpu_arch="x86"
        ;;
     i[3467]86*-msdosdjgpp* | \
     i[34]86*-apple-darwin*)
        echo '#define BSD_SYNTAX'        >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h   >>./mpi/asm-syntax.h
        path="i386"
+        mpi_cpu_arch="x86"
        ;;
     i586*-msdosdjgpp* | \
     i[567]86*-apple-darwin*)
        echo '#define BSD_SYNTAX'        >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h   >>./mpi/asm-syntax.h
        path="i586 i386"
+        mpi_cpu_arch="x86"
        ;;
     i[3467]86*-*-*)
        echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h      >>./mpi/asm-syntax.h
        path="i386"
+        mpi_cpu_arch="x86"
        ;;
     i586*-*-*  | \
     pentium-*-*   | \
@@ -111,16 +122,19 @@ case "${host}" in
        echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h      >>./mpi/asm-syntax.h
        path="i586 i386"
+        mpi_cpu_arch="x86"
        ;;
     x86_64-*-*)
        echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/i386/syntax.h      >>./mpi/asm-syntax.h
        path="amd64"
+        mpi_cpu_arch="x86"
        ;;
     alpha*-*-*)
        echo '/* configured for alpha */' >>./mpi/asm-syntax.h
        path="alpha"
        mpi_extra_modules="udiv-qrnnd"
+        mpi_cpu_arch="alpha"
        ;;
     hppa7000*-*-*)
        echo '/* configured for HPPA (pa7000) */' >>./mpi/asm-syntax.h
@@ -140,49 +154,59 @@ case "${host}" in
     sparc64-*-linux-gnu)
         echo '/* No working assembler modules available */' >>./mpi/asm-syntax.h
        path=""
+        mpi_cpu_arch="sparc"
        ;;
     sparc64-sun-solaris2*)
         echo '/* No working assembler modules available */' >>./mpi/asm-syntax.h
        path=""
+        mpi_cpu_arch="sparc"
         ;;
     sparc64-*-netbsd* | sparc64-*-freebsd* | sparc64-*-openbsd*)
        # There are no sparc64 assembler modules that work on the
        # *BSDs, so use the generic C functions.
        echo '/* No working assembler modules available */' >>./mpi/asm-syntax.h
        path=""
+       mpi_cpu_arch="sparc"
        ;;
     sparc64*-*-*)
        echo '/* No working assembler modules available */' >>./mpi/asm-syntax.h
        path=""
+       mpi_cpu_arch="sparc"
        ;;
     sparc9*-*-*     | \
     ultrasparc*-*-* )
        echo '/* configured for sparc9 or higher */' >>./mpi/asm-syntax.h
        path="sparc32v8 sparc32"
+        mpi_cpu_arch="sparc"
        ;;
     sparc8*-*-*     | \
     microsparc*-*-*)
        echo '/* configured for sparc8 */' >>./mpi/asm-syntax.h
        path="sparc32v8 sparc32"
+        mpi_cpu_arch="sparc"
        ;;
     supersparc*-*-*)
        echo '/* configured for supersparc */' >>./mpi/asm-syntax.h
        path="supersparc sparc32v8 sparc32"
        mpi_extra_modules="udiv"
+        mpi_cpu_arch="sparc"
        ;;
     sparc*-*-*)
        echo '/* configured for sparc */' >>./mpi/asm-syntax.h
        path="sparc32"
        mpi_extra_modules="udiv"
+        mpi_cpu_arch="sparc"
        ;;
     mips[34]*-*-* | \
     mips*-*-irix6*)
        echo '/* configured for MIPS3 */' >>./mpi/asm-syntax.h
        path="mips3"
+       mpi_cpu_arch="mips"
        ;;
     mips*-*-*)
        echo '/* configured for MIPS2 */' >>./mpi/asm-syntax.h
        path="mips2"
+       mpi_cpu_arch="mips"
        ;;
 
     # Motorola 68k configurations.  Let m68k mean 68020-68040.
@@ -192,38 +216,45 @@ case "${host}" in
        echo '#define MIT_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
        path="m68k/mc68020 m68k"
+        mpi_cpu_arch="m68k"
        ;;
     m68060*-*-linuxaout*)
        echo '#define MIT_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
        path="m68k"
+        mpi_cpu_arch="m68k"
        ;;
     m680[234]0*-*-linux* | \
     m68k*-*-linux*)
        echo '#define ELF_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
+        mpi_cpu_arch="m68k"
        ;;
     m68060*-*-linux*)
        echo '#define ELF_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
        path="m68k"
+        mpi_cpu_arch="m68k"
        ;;
     m68k-atari-mint)
        echo '#define MIT_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
        path="m68k/mc68020 m68k"
+        mpi_cpu_arch="m68k"
        ;;
     m68000*-*-* | \
     m68060*-*-*)
        echo '#define MIT_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
        path="m68k/mc68000"
+        mpi_cpu_arch="m68k"
        ;;
     m680[234]0*-*-* | \
     m68k*-*-*)
        echo '#define MIT_SYNTAX'           >>./mpi/asm-syntax.h
        cat  $srcdir/mpi/m68k/syntax.h      >>./mpi/asm-syntax.h
        path="m68k/mc68020 m68k"
+        mpi_cpu_arch="m68k"
        ;;
 
     powerpc*-*-netbsd* | powerpc*-*-openbsd*)
@@ -232,18 +263,21 @@ case "${host}" in
        cat   $srcdir/mpi/powerpc32/syntax.h     >>./mpi/asm-syntax.h
        mpi_sflags="-Wa,-mppc"
        path="powerpc32"
+       mpi_cpu_arch="ppc"
        ;;
 
     ppc620-*-*     | \
     powerpc64*-*-*)
        mpi_sflags="-Wa,-mppc"
        path="powerpc64"
+        mpi_cpu_arch="ppc"
        ;;
     powerpc*-*-linux*)
        echo '/* configured for powerpc/ELF */' >>./mpi/asm-syntax.h
        echo '#define ELF_SYNTAX'               >>./mpi/asm-syntax.h
        cat   $srcdir/mpi/powerpc32/syntax.h    >>./mpi/asm-syntax.h
        path="powerpc32"
+       mpi_cpu_arch="ppc"
        ;;
 
     rs6000-*-aix[456789]*    | \
@@ -258,6 +292,7 @@ case "${host}" in
        mpi_sflags="-Wa,-mppc"
        path="power"
        mpi_extra_modules="udiv-w-sdiv"
+        mpi_cpu_arch="ppc"
        ;;
     powerpc-ibm-aix4.2.* )
        # I am not sure about this one but a machine identified by
@@ -265,18 +300,22 @@ case "${host}" in
        mpi_sflags="-Wa,-mpwr"
        path="power"
        mpi_extra_modules="udiv-w-sdiv"
+        mpi_cpu_arch="ppc"
        ;;
     ppc601-*-*)
        mpi_sflags="-Wa,-mppc"
        path="power powerpc32"
+        mpi_cpu_arch="ppc"
        ;;
     ppc60[234]*-*-*)
        mpi_sflags="-Wa,-mppc"
        path="powerpc32"
+        mpi_cpu_arch="ppc"
        ;;
     powerpc*-*-*)
        mpi_sflags="-Wa,-mppc"
        path="powerpc32"
+        mpi_cpu_arch="ppc"
        ;;
     *)
        echo '/* No assembler modules configured */' >>./mpi/asm-syntax.h
index 2a07067..cdfe0c6 100644 (file)
@@ -54,12 +54,16 @@ endif
 libgcrypt_la_CFLAGS = $(GPG_ERROR_CFLAGS)
 libgcrypt_la_SOURCES = g10lib.h visibility.c visibility.h types.h \
        cipher.h cipher-proto.h gcrypt-module.h \
-       misc.c global.c sexp.c hwfeatures.c \
+       misc.c global.c sexp.c hwfeatures.c hwf-common.h \
        stdmem.c stdmem.h secmem.c secmem.h \
        mpi.h missing-string.c module.c fips.c \
        hmac256.c hmac256.h \
        ath.h ath.c
 
+EXTRA_libgcrypt_la_SOURCES = hwf-x86.c
+gcrypt_hwf_modules = @GCRYPT_HWF_MODULES@
+
+
 if HAVE_W32_SYSTEM
 
 RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
@@ -101,12 +105,14 @@ libgcrypt_la_LDFLAGS = $(no_undefined) $(export_symbols) \
        $(libgcrypt_version_script_cmd) -version-info \
        @LIBGCRYPT_LT_CURRENT@:@LIBGCRYPT_LT_REVISION@:@LIBGCRYPT_LT_AGE@
 libgcrypt_la_DEPENDENCIES = \
+         $(gcrypt_hwf_modules)
        ../cipher/libcipher.la \
        ../random/librandom.la \
        ../mpi/libmpi.la \
        ../compat/libcompat.la \
        $(srcdir)/libgcrypt.vers $(gcrypt_deps)
 libgcrypt_la_LIBADD = $(gcrypt_res) \
+        $(gcrypt_hwf_modules) \
        ../cipher/libcipher.la \
        ../random/librandom.la \
        ../mpi/libmpi.la \
index 2428e21..b701dfc 100644 (file)
@@ -299,6 +299,23 @@ print_config ( int (*fnc)(FILE *fp, const char *format, ...), FILE *fp)
                 "w32:"
 #endif
        "\n");
+  fnc (fp, "cpu-arch:"
+#if defined(HAVE_CPU_ARCH_X86)
+       "x86"
+#elif defined(HAVE_CPU_ARCH_ALPHA)
+       "alpha"
+#elif defined(HAVE_CPU_ARCH_SPARC)
+       "sparc"
+#elif defined(HAVE_CPU_ARCH_MIPS)
+       "mips"
+#elif defined(HAVE_CPU_ARCH_M68K)
+       "m68k"
+#elif defined(HAVE_CPU_ARCH_PPC)
+       "ppc"
+#elif defined(HAVE_CPU_ARCH_ARM)
+       "arm"
+#endif
+       ":\n");
   fnc (fp, "mpi-asm:%s:\n", _gcry_mpi_get_hw_config ());
   fnc (fp, "threads:%s:\n", ath_get_model (NULL));
   hwf = _gcry_get_hw_features ();
diff --git a/src/hwf-common.h b/src/hwf-common.h
new file mode 100644 (file)
index 0000000..974f47d
--- /dev/null
@@ -0,0 +1,26 @@
+/* hwf-common.h - Declarations for hwf-CPU.c modules
+ * Copyright (C) 2012  g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HWF_COMMON_H
+#define HWF_COMMON_H
+
+unsigned int _gcry_hwf_detect_x86 (void);
+
+
+#endif /*HWF_COMMON_H*/
diff --git a/src/hwf-x86.c b/src/hwf-x86.c
new file mode 100644 (file)
index 0000000..b50b4b0
--- /dev/null
@@ -0,0 +1,226 @@
+/* hwf-x86.c - Detect hardware features - x86 part
+ * Copyright (C) 2007, 2011, 2012  Free Software Foundation, Inc.
+ * Copyright (C) 2012  Jussi Kivilinna
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "g10lib.h"
+#include "hwf-common.h"
+
+#if !defined (__i386__) && !defined (__x86_64__)
+# error Module build for wrong CPU.
+#endif
+
+/* We use the next macro to decide whether we can test for certain
+   features.  */
+#undef HAS_X86_CPUID
+
+#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__)
+# define HAS_X86_CPUID 1
+
+static int
+is_cpuid_available(void)
+{
+  int has_cpuid = 0;
+
+  /* Detect the CPUID feature by testing some undefined behaviour (16
+     vs 32 bit pushf/popf). */
+  asm volatile
+    ("pushf\n\t"                 /* Copy flags to EAX.  */
+     "popl %%eax\n\t"
+     "movl %%eax, %%ecx\n\t"     /* Save flags into ECX.  */
+     "xorl $0x200000, %%eax\n\t" /* Toggle ID bit and copy it to the flags.  */
+     "pushl %%eax\n\t"
+     "popf\n\t"
+     "pushf\n\t"                 /* Copy changed flags again to EAX.  */
+     "popl %%eax\n\t"
+     "pushl %%ecx\n\t"           /* Restore flags from ECX.  */
+     "popf\n\t"
+     "xorl %%eax, %%ecx\n\t"     /* Compare flags against saved flags.  */
+     "jz .Lno_cpuid%=\n\t"       /* Toggling did not work, thus no CPUID.  */
+     "movl $1, %0\n"             /* Worked. true -> HAS_CPUID.  */
+     ".Lno_cpuid%=:\n\t"
+     : "+r" (has_cpuid)
+     :
+     : "%eax", "%ecx", "cc"
+     );
+
+  return has_cpuid;
+}
+
+static void
+get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
+          unsigned int *ecx, unsigned int *edx)
+{
+  unsigned int regs[4];
+
+  asm volatile
+    ("pushl %%ebx\n\t"           /* Save GOT register.  */
+     "cpuid\n\t"
+     "movl %%ebx, %1\n\t"
+     "popl %%ebx\n\t"            /* Restore GOT register. */
+     : "=a" (regs[0]), "=r" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
+     : "0" (in)
+     : "cc"
+     );
+
+  if (eax)
+    *eax = regs[0];
+  if (ebx)
+    *ebx = regs[1];
+  if (ecx)
+    *ecx = regs[2];
+  if (edx)
+    *edx = regs[3];
+}
+#endif /* i386 && GNUC */
+
+
+#if defined (__x86_64__) && defined (__GNUC__)
+# define HAS_X86_CPUID 1
+
+static int
+is_cpuid_available(void)
+{
+  return 1;
+}
+
+static void
+get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
+          unsigned int *ecx, unsigned int *edx)
+{
+  unsigned int regs[4];
+
+  asm volatile
+    ("cpuid\n\t"
+     : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
+     : "0" (in)
+     : "cc"
+     );
+
+  if (eax)
+    *eax = regs[0];
+  if (ebx)
+    *ebx = regs[1];
+  if (ecx)
+    *ecx = regs[2];
+  if (edx)
+    *edx = regs[3];
+}
+#endif /* x86-64 && GNUC */
+
+
+#ifdef HAS_X86_CPUID
+static unsigned int
+detect_x86_gnuc (void)
+{
+  char vendor_id[12+1];
+  unsigned int features;
+  unsigned int result = 0;
+
+  if (!is_cpuid_available())
+    return 0;
+
+  get_cpuid(0, NULL,
+            (unsigned int *)&vendor_id[0],
+            (unsigned int *)&vendor_id[8],
+            (unsigned int *)&vendor_id[4]);
+  vendor_id[12] = 0;
+
+  if (0)
+    ; /* Just to make "else if" and ifdef macros look pretty.  */
+#ifdef ENABLE_PADLOCK_SUPPORT
+  else if (!strcmp (vendor_id, "CentaurHauls"))
+    {
+      /* This is a VIA CPU.  Check what PadLock features we have.  */
+
+      /* Check for extended centaur (EAX).  */
+      get_cpuid(0xC0000000, &features, NULL, NULL, NULL);
+
+      /* Has extended centaur features? */
+      if (features > 0xC0000000)
+        {
+           /* Ask for the extended feature flags (EDX). */
+           get_cpuid(0xC0000001, NULL, NULL, NULL, &features);
+
+           /* Test bits 2 and 3 to see whether the RNG exists and is enabled. */
+           if ((features & 0x0C) == 0x0C)
+             result |= HWF_PADLOCK_RNG;
+
+           /* Test bits 6 and 7 to see whether the ACE exists and is enabled. */
+           if ((features & 0xC0) == 0xC0)
+             result |= HWF_PADLOCK_AES;
+
+           /* Test bits 10 and 11 to see whether the PHE exists and is
+              enabled.  */
+           if ((features & 0xC00) == 0xC00)
+             result |= HWF_PADLOCK_SHA;
+
+           /* Test bits 12 and 13 to see whether the MONTMUL exists and is
+              enabled.  */
+           if ((features & 0x3000) == 0x3000)
+             result |= HWF_PADLOCK_MMUL;
+        }
+    }
+#endif /*ENABLE_PADLOCK_SUPPORT*/
+  else if (!strcmp (vendor_id, "GenuineIntel"))
+    {
+      /* This is an Intel CPU.  */
+    }
+  else if (!strcmp (vendor_id, "AuthenticAMD"))
+    {
+      /* This is an AMD CPU.  */
+    }
+
+  /* Detect Intel features, that might also be supported by other
+     vendors.  */
+
+  /* Get CPU info and Intel feature flags (ECX).  */
+  get_cpuid(1, NULL, NULL, &features, NULL);
+
+#ifdef ENABLE_AESNI_SUPPORT
+  /* Test bit 25 for AES-NI.  */
+  if (features & 0x02000000)
+     result |= HWF_INTEL_AESNI;
+#endif /*ENABLE_AESNI_SUPPORT*/
+#ifdef ENABLE_DRNG_SUPPORT
+  /* Test bit 30 for RDRAND.  */
+  if (features & 0x40000000)
+     result |= HWF_INTEL_RDRAND;
+#endif /*ENABLE_DRNG_SUPPORT*/
+
+  return result;
+}
+#endif /* HAS_X86_CPUID */
+
+
+unsigned int
+_gcry_hwf_detect_x86 (void)
+{
+#if defined (HAS_X86_CPUID)
+  return detect_x86_gnuc ();
+#else
+  return 0;
+#endif
+}
index 62600aa..87d05d8 100644 (file)
@@ -1,5 +1,6 @@
 /* hwfeatures.c - Detect hardware features.
  * Copyright (C) 2007, 2011  Free Software Foundation, Inc.
+ * Copyright (C) 2012  g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -25,6 +26,8 @@
 #include <unistd.h>
 
 #include "g10lib.h"
+#include "hwf-common.h"
+
 
 /* A bit vector describing the hardware features currently
    available. */
@@ -40,185 +43,6 @@ _gcry_get_hw_features (void)
 }
 
 
-#undef HAS_X86_CPUID
-
-#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__)
-#define HAS_X86_CPUID 1
-
-static int
-is_cpuid_available(void)
-{
-  int has_cpuid = 0;
-
-  /* Detect the CPUID feature by testing some undefined behaviour (16
-     vs 32 bit pushf/popf). */
-  asm volatile
-    ("pushf\n\t"                 /* Copy flags to EAX.  */
-     "popl %%eax\n\t"
-     "movl %%eax, %%ecx\n\t"     /* Save flags into ECX.  */
-     "xorl $0x200000, %%eax\n\t" /* Toggle ID bit and copy it to the flags.  */
-     "pushl %%eax\n\t"
-     "popf\n\t"
-     "pushf\n\t"                 /* Copy changed flags again to EAX.  */
-     "popl %%eax\n\t"
-     "pushl %%ecx\n\t"           /* Restore flags from ECX.  */
-     "popf\n\t"
-     "xorl %%eax, %%ecx\n\t"     /* Compare flags against saved flags.  */
-     "jz .Lno_cpuid%=\n\t"       /* Toggling did not work, thus no CPUID.  */
-     "movl $1, %0\n"             /* Worked. true -> HAS_CPUID.  */
-     ".Lno_cpuid%=:\n\t"
-     : "+r" (has_cpuid)
-     :
-     : "%eax", "%ecx", "cc"
-     );
-
-  return has_cpuid;
-}
-
-static void
-get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
-          unsigned int *ecx, unsigned int *edx)
-{
-  unsigned int regs[4];
-
-  asm volatile
-    ("pushl %%ebx\n\t"           /* Save GOT register.  */
-     "cpuid\n\t"
-     "movl %%ebx, %1\n\t"
-     "popl %%ebx\n\t"            /* Restore GOT register. */
-     : "=a" (regs[0]), "=r" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
-     : "0" (in)
-     : "cc"
-     );
-
-  if (eax)
-    *eax = regs[0];
-  if (ebx)
-    *ebx = regs[1];
-  if (ecx)
-    *ecx = regs[2];
-  if (edx)
-    *edx = regs[3];
-}
-#endif /* i386 && GNUC */
-
-
-#if defined (__x86_64__) && defined (__GNUC__)
-#define HAS_X86_CPUID 1
-
-static int
-is_cpuid_available(void)
-{
-  return 1;
-}
-
-static void
-get_cpuid(unsigned int in, unsigned int *eax, unsigned int *ebx,
-          unsigned int *ecx, unsigned int *edx)
-{
-  unsigned int regs[4];
-
-  asm volatile
-    ("cpuid\n\t"
-     : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
-     : "0" (in)
-     : "cc"
-     );
-
-  if (eax)
-    *eax = regs[0];
-  if (ebx)
-    *ebx = regs[1];
-  if (ecx)
-    *ecx = regs[2];
-  if (edx)
-    *edx = regs[3];
-}
-#endif /* x86-64 && GNUC */
-
-
-#ifdef HAS_X86_CPUID
-static void
-detect_x86_gnuc (void)
-{
-  char vendor_id[12+1];
-  unsigned int features;
-
-  if (!is_cpuid_available())
-    return;
-
-  get_cpuid(0, NULL,
-            (unsigned int *)&vendor_id[0],
-            (unsigned int *)&vendor_id[8],
-            (unsigned int *)&vendor_id[4]);
-  vendor_id[12] = 0;
-
-  if (0)
-    ; /* Just to make "else if" and ifdef macros look pretty.  */
-#ifdef ENABLE_PADLOCK_SUPPORT
-  else if (!strcmp (vendor_id, "CentaurHauls"))
-    {
-      /* This is a VIA CPU.  Check what PadLock features we have.  */
-
-      /* Check for extended centaur (EAX).  */
-      get_cpuid(0xC0000000, &features, NULL, NULL, NULL);
-
-      /* Has extended centaur features? */
-      if (features > 0xC0000000)
-        {
-           /* Ask for the extended feature flags (EDX). */
-           get_cpuid(0xC0000001, NULL, NULL, NULL, &features);
-
-           /* Test bits 2 and 3 to see whether the RNG exists and is enabled. */
-           if ((features & 0x0C) == 0x0C)
-             hw_features |= HWF_PADLOCK_RNG;
-
-           /* Test bits 6 and 7 to see whether the ACE exists and is enabled. */
-           if ((features & 0xC0) == 0xC0)
-             hw_features |= HWF_PADLOCK_AES;
-
-           /* Test bits 10 and 11 to see whether the PHE exists and is
-              enabled.  */
-           if ((features & 0xC00) == 0xC00)
-             hw_features |= HWF_PADLOCK_SHA;
-
-           /* Test bits 12 and 13 to see whether the MONTMUL exists and is
-              enabled.  */
-           if ((features & 0x3000) == 0x3000)
-             hw_features |= HWF_PADLOCK_MMUL;
-        }
-    }
-#endif /*ENABLE_PADLOCK_SUPPORT*/
-  else if (!strcmp (vendor_id, "GenuineIntel"))
-    {
-      /* This is an Intel CPU.  */
-    }
-  else if (!strcmp (vendor_id, "AuthenticAMD"))
-    {
-      /* This is an AMD CPU.  */
-    }
-
-  /* Detect Intel features, that might also be supported by other
-     vendors.  */
-
-  /* Get CPU info and Intel feature flags (ECX).  */
-  get_cpuid(1, NULL, NULL, &features, NULL);
-
-#ifdef ENABLE_AESNI_SUPPORT
-  /* Test bit 25 for AES-NI.  */
-  if (features & 0x02000000)
-     hw_features |= HWF_INTEL_AESNI;
-#endif /*ENABLE_AESNI_SUPPORT*/
-#ifdef ENABLE_DRNG_SUPPORT
-  /* Test bit 30 for RDRAND.  */
-  if (features & 0x40000000)
-     hw_features |= HWF_INTEL_RDRAND;
-#endif /*ENABLE_DRNG_SUPPORT*/
-
-}
-#endif /* HAS_X86_CPUID */
-
-
 /* Detect the available hardware features.  This function is called
    once right at startup and we assume that no other threads are
    running.  */
@@ -230,11 +54,11 @@ _gcry_detect_hw_features (unsigned int disabled_features)
   if (fips_mode ())
     return; /* Hardware support is not to be evaluated.  */
 
-#if HAS_X86_CPUID
+#if defined (HAVE_CPU_ARCH_X86)
   {
-    detect_x86_gnuc ();
+    hw_features = _gcry_hwf_detect_x86 ();
   }
-#endif /* HAS_X86_CPUID */
+#endif /* HAVE_CPU_ARCH_X86 */
 
   hw_features &= ~disabled_features;
 }