summaryrefslogtreecommitdiff
path: root/src/hwfeatures.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-11-29 10:55:46 +0000
committerWerner Koch <wk@gnupg.org>2007-11-29 10:55:46 +0000
commitf1c4026ae146419f5112cc355a92107f7ca13abe (patch)
tree78ce43f4fea4bb94e48ef3ad883dbfa2be3e2ee6 /src/hwfeatures.c
parentceb9f97eff920b1d986e28468b73919b2abfffc7 (diff)
downloadlibgcrypt-f1c4026ae146419f5112cc355a92107f7ca13abe.tar.gz
The ACE engine of VIA processors is now used for AES-128.
Diffstat (limited to 'src/hwfeatures.c')
-rw-r--r--src/hwfeatures.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/hwfeatures.c b/src/hwfeatures.c
index 3594c0b3..6908c587 100644
--- a/src/hwfeatures.c
+++ b/src/hwfeatures.c
@@ -44,10 +44,102 @@ _gcry_get_hw_features (void)
static void
detect_ia32_gnuc (void)
{
+ 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. */
+ "leal %0, %%eax\n\t" /* EBX,EDX,ECX -> VENDOR_ID. */
+ "movl %%ebx, (%%eax)\n\t"
+ "movl %%edx, 4(%%eax)\n\t"
+ "movl %%ecx, 8(%%eax)\n\t"
+ "popl %%ebx\n"
+ : "=m" (vendor_id)
+ :
+ : "%eax", "%ecx", "%edx", "cc"
+ );
+ vendor_id[12] = 0;
+
+ /* Check whether this is a VIA CPU and what PadLock features we
+ have. */
+ if (!strcmp (vendor_id, "CentaurHauls"))
+ {
+ 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 /* __i386__ && SIZEOF_UNSIGNED_LONG == 4 && __GNUC__ */
@@ -58,6 +150,8 @@ detect_ia32_gnuc (void)
void
_gcry_detect_hw_features (void)
{
+ hw_features = 0;
+
#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4
#ifdef __GNUC__
detect_ia32_gnuc ();