192 lines
6.5 KiB
C
192 lines
6.5 KiB
C
/* hwfeatures.c - Detect hardware features.
|
|
* Copyright (C) 2007, 2011 Free Software Foundation, Inc.
|
|
*
|
|
* 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"
|
|
|
|
/* A bit vector describing the hardware features currently
|
|
available. */
|
|
static unsigned int hw_features;
|
|
|
|
|
|
/* Return a bit vector describing the available hardware features.
|
|
The HWF_ constants are used to test for them. */
|
|
unsigned int
|
|
_gcry_get_hw_features (void)
|
|
{
|
|
return hw_features;
|
|
}
|
|
|
|
|
|
#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__)
|
|
static void
|
|
detect_ia32_gnuc (void)
|
|
{
|
|
/* The code here is only useful for the PadLock engine thus we don't
|
|
build it if that support has been disabled. */
|
|
int has_cpuid = 0;
|
|
char vendor_id[12+1];
|
|
|
|
/* 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"
|
|
);
|
|
|
|
if (!has_cpuid)
|
|
return; /* No way. */
|
|
|
|
asm volatile
|
|
("pushl %%ebx\n\t" /* Save GOT register. */
|
|
"xorl %%eax, %%eax\n\t" /* 0 -> EAX. */
|
|
"cpuid\n\t" /* Get vendor ID. */
|
|
"movl %%ebx, (%0)\n\t" /* EBX,EDX,ECX -> VENDOR_ID. */
|
|
"movl %%edx, 4(%0)\n\t"
|
|
"movl %%ecx, 8(%0)\n\t"
|
|
"popl %%ebx\n"
|
|
:
|
|
: "S" (&vendor_id[0])
|
|
: "%eax", "%ecx", "%edx", "cc"
|
|
);
|
|
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. */
|
|
asm volatile
|
|
("pushl %%ebx\n\t" /* Save GOT register. */
|
|
"movl $0xC0000000, %%eax\n\t" /* Check for extended centaur */
|
|
"cpuid\n\t" /* feature flags. */
|
|
"popl %%ebx\n\t" /* Restore GOT register. */
|
|
"cmpl $0xC0000001, %%eax\n\t"
|
|
"jb .Lready%=\n\t" /* EAX < 0xC0000000 => no padlock. */
|
|
|
|
"pushl %%ebx\n\t" /* Save GOT register. */
|
|
"movl $0xC0000001, %%eax\n\t" /* Ask for the extended */
|
|
"cpuid\n\t" /* feature flags. */
|
|
"popl %%ebx\n\t" /* Restore GOT register. */
|
|
|
|
"movl %%edx, %%eax\n\t" /* Take copy of feature flags. */
|
|
"andl $0x0C, %%eax\n\t" /* Test bits 2 and 3 to see whether */
|
|
"cmpl $0x0C, %%eax\n\t" /* the RNG exists and is enabled. */
|
|
"jnz .Lno_rng%=\n\t"
|
|
"orl $1, %0\n" /* Set our HWF_PADLOCK_RNG bit. */
|
|
|
|
".Lno_rng%=:\n\t"
|
|
"movl %%edx, %%eax\n\t" /* Take copy of feature flags. */
|
|
"andl $0xC0, %%eax\n\t" /* Test bits 6 and 7 to see whether */
|
|
"cmpl $0xC0, %%eax\n\t" /* the ACE exists and is enabled. */
|
|
"jnz .Lno_ace%=\n\t"
|
|
"orl $2, %0\n" /* Set our HWF_PADLOCK_AES bit. */
|
|
|
|
".Lno_ace%=:\n\t"
|
|
"movl %%edx, %%eax\n\t" /* Take copy of feature flags. */
|
|
"andl $0xC00, %%eax\n\t" /* Test bits 10, 11 to see whether */
|
|
"cmpl $0xC00, %%eax\n\t" /* the PHE exists and is enabled. */
|
|
"jnz .Lno_phe%=\n\t"
|
|
"orl $4, %0\n" /* Set our HWF_PADLOCK_SHA bit. */
|
|
|
|
".Lno_phe%=:\n\t"
|
|
"movl %%edx, %%eax\n\t" /* Take copy of feature flags. */
|
|
"andl $0x3000, %%eax\n\t" /* Test bits 12, 13 to see whether */
|
|
"cmpl $0x3000, %%eax\n\t" /* MONTMUL exists and is enabled. */
|
|
"jnz .Lready%=\n\t"
|
|
"orl $8, %0\n" /* Set our HWF_PADLOCK_MMUL bit. */
|
|
|
|
".Lready%=:\n"
|
|
: "+r" (hw_features)
|
|
:
|
|
: "%eax", "%edx", "cc"
|
|
);
|
|
}
|
|
#endif /*ENABLE_PADLOCK_SUPPORT*/
|
|
else if (!strcmp (vendor_id, "GenuineIntel"))
|
|
{
|
|
/* This is an Intel CPU. */
|
|
asm volatile
|
|
("pushl %%ebx\n\t" /* Save GOT register. */
|
|
"movl $1, %%eax\n\t" /* Get CPU info and feature flags. */
|
|
"cpuid\n"
|
|
"popl %%ebx\n\t" /* Restore GOT register. */
|
|
"testl $0x02000000, %%ecx\n\t" /* Test bit 25. */
|
|
"jz .Lno_aes%=\n\t" /* No AES support. */
|
|
"orl $256, %0\n" /* Set our HWF_INTEL_AES bit. */
|
|
|
|
".Lno_aes%=:\n"
|
|
: "+r" (hw_features)
|
|
:
|
|
: "%eax", "%ecx", "%edx", "cc"
|
|
);
|
|
}
|
|
else if (!strcmp (vendor_id, "AuthenticAMD"))
|
|
{
|
|
/* This is an AMD CPU. */
|
|
|
|
}
|
|
}
|
|
#endif /* __i386__ && SIZEOF_UNSIGNED_LONG == 4 && __GNUC__ */
|
|
|
|
|
|
/* Detect the available hardware features. This function is called
|
|
once right at startup and we assume that no other threads are
|
|
running. */
|
|
void
|
|
_gcry_detect_hw_features (unsigned int disabled_features)
|
|
{
|
|
hw_features = 0;
|
|
|
|
if (fips_mode ())
|
|
return; /* Hardware support is not to be evaluated. */
|
|
|
|
#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4
|
|
#ifdef __GNUC__
|
|
detect_ia32_gnuc ();
|
|
#endif
|
|
#elif defined (__i386__) && SIZEOF_UNSIGNED_LONG == 8
|
|
#ifdef __GNUC__
|
|
#endif
|
|
#endif
|
|
|
|
hw_features &= ~disabled_features;
|
|
}
|