Changed the way the FIPS RNG is seeded.
[libgcrypt.git] / src / hwfeatures.c
1 /* hwfeatures.c - Detect hardware features.
2  * Copyright (C) 2007  Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26
27 #include "g10lib.h"
28
29 /* A bit vector describing the hardware features currently
30    available. */
31 static unsigned int hw_features;
32
33
34 /* Return a bit vector describing the available hardware features.
35    The HWF_ constants are used to test for them. */
36 unsigned int
37 _gcry_get_hw_features (void)
38 {
39   return hw_features;
40 }
41
42
43 #if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__)
44 static void
45 detect_ia32_gnuc (void)
46 {
47 #ifdef ENABLE_PADLOCK_SUPPORT  
48   /* The code here is only useful for the PadLock engine thus we don't
49      build it if that support has been disabled.  */
50   int has_cpuid = 0;
51   char vendor_id[12+1];
52   
53   /* Detect the CPUID feature by testing some undefined behaviour (16
54      vs 32 bit pushf/popf). */
55   asm volatile
56     ("pushf\n\t"                 /* Copy flags to EAX.  */
57      "popl %%eax\n\t"
58      "movl %%eax, %%ecx\n\t"     /* Save flags into ECX.  */
59      "xorl $0x200000, %%eax\n\t" /* Toggle ID bit and copy it to the flags.  */
60      "pushl %%eax\n\t"            
61      "popf\n\t"                
62      "pushf\n\t"                 /* Copy changed flags again to EAX.  */    
63      "popl %%eax\n\t"
64      "pushl %%ecx\n\t"           /* Restore flags from ECX.  */
65      "popf\n\t"
66      "xorl %%eax, %%ecx\n\t"     /* Compare flags against saved flags.  */
67      "jz .Lno_cpuid%=\n\t"       /* Toggling did not work, thus no CPUID.  */
68      "movl $1, %0\n"             /* Worked. true -> HAS_CPUID.  */
69      ".Lno_cpuid%=:\n\t"
70      : "=r" (has_cpuid)
71      :
72      : "%eax", "%ecx", "cc"
73      );
74   
75   if (!has_cpuid)
76     return;  /* No way.  */
77            
78   asm volatile
79     ("pushl %%ebx\n\t"           /* Save GOT register.  */
80      "xorl  %%eax, %%eax\n\t"    /* 0 -> EAX.  */
81      "cpuid\n\t"                 /* Get vendor ID.  */
82      "movl  %%ebx, (%0)\n\t"     /* EBX,EDX,ECX -> VENDOR_ID.  */
83      "movl  %%edx, 4(%0)\n\t"
84      "movl  %%ecx, 8(%0)\n\t"
85      "popl  %%ebx\n"
86      :
87      : "S" (&vendor_id[0])
88      : "%eax", "%ecx", "%edx", "cc"
89      );
90   vendor_id[12] = 0;
91
92   /* Check whether this is a VIA CPU and what PadLock features we
93      have.  */
94   if (!strcmp (vendor_id, "CentaurHauls"))
95     {
96       asm volatile 
97         ("pushl %%ebx\n\t"              /* Save GOT register.  */
98          "movl $0xC0000000, %%eax\n\t"  /* Check for extended centaur  */
99          "cpuid\n\t"                    /* feature flags.              */
100          "popl %%ebx\n\t"               /* Restore GOT register. */
101          "cmpl $0xC0000001, %%eax\n\t"
102          "jb .Lready%=\n\t"             /* EAX < 0xC0000000 => no padlock.  */
103
104          "pushl %%ebx\n\t"              /* Save GOT register. */
105          "movl $0xC0000001, %%eax\n\t"  /* Ask for the extended */
106          "cpuid\n\t"                    /* feature flags.       */
107          "popl %%ebx\n\t"               /* Restore GOT register. */
108
109          "movl %%edx, %%eax\n\t"        /* Take copy of feature flags.  */
110          "andl $0x0C, %%eax\n\t"        /* Test bits 2 and 3 to see whether */
111          "cmpl $0x0C, %%eax\n\t"        /* the RNG exists and is enabled.   */
112          "jnz .Lno_rng%=\n\t"
113          "orl $1, %0\n"                 /* Set our HWF_PADLOCK_RNG bit.  */
114
115          ".Lno_rng%=:\n\t"
116          "movl %%edx, %%eax\n\t"        /* Take copy of feature flags.  */
117          "andl $0xC0, %%eax\n\t"        /* Test bits 6 and 7 to see whether */
118          "cmpl $0xC0, %%eax\n\t"        /* the ACE exists and is enabled.   */
119          "jnz .Lno_ace%=\n\t"
120          "orl $2, %0\n"                 /* Set our HWF_PADLOCK_AES bit.  */
121
122          ".Lno_ace%=:\n\t"
123          "movl %%edx, %%eax\n\t"        /* Take copy of feature flags.  */
124          "andl $0xC00, %%eax\n\t"       /* Test bits 10, 11 to see whether  */
125          "cmpl $0xC00, %%eax\n\t"       /* the PHE exists and is enabled.   */
126          "jnz .Lno_phe%=\n\t"
127          "orl $4, %0\n"                 /* Set our HWF_PADLOCK_SHA bit.  */
128
129          ".Lno_phe%=:\n\t"
130          "movl %%edx, %%eax\n\t"        /* Take copy of feature flags.  */
131          "andl $0x3000, %%eax\n\t"      /* Test bits 12, 13 to see whether  */
132          "cmpl $0x3000, %%eax\n\t"      /* MONTMUL exists and is enabled.   */
133          "jnz .Lready%=\n\t"
134          "orl $8, %0\n"                 /* Set our HWF_PADLOCK_MMUL bit.  */
135
136          ".Lready%=:\n"
137          : "+r" (hw_features)
138          :
139          : "%eax", "%edx", "cc"
140          );
141     }
142 #endif /*ENABLE_PADLOCK_SUPPORT*/
143 }
144 #endif /* __i386__ && SIZEOF_UNSIGNED_LONG == 4 && __GNUC__ */
145
146
147
148 /* Detect the available hardware features.  This function is called
149    once right at startup and we assume that no other threads are
150    running.  */
151 void
152 _gcry_detect_hw_features (void)
153 {
154   hw_features = 0;
155
156   if (fips_mode ())
157     return; /* Hardware support is not to be evaluated.  */ 
158
159 #if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4
160 #ifdef __GNUC__  
161   detect_ia32_gnuc ();
162 #endif
163 #elif defined (__i386__) && SIZEOF_UNSIGNED_LONG == 8
164 #ifdef __GNUC__  
165 #endif
166 #endif
167 }