Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Cryptographic API.
  3  *
  4  * Support for VIA PadLock hardware crypto engine.
  5  *
  6  * Copyright (c) 2006  Michal Ludvig <michal@logix.cz>
  7  *
  8  * This program is free software; you can redistribute it and/or modify
  9  * it under the terms of the GNU General Public License as published by
 10  * the Free Software Foundation; either version 2 of the License, or
 11  * (at your option) any later version.
 12  *
 13  */
 14 
 15 #include <crypto/algapi.h>
 16 #include <crypto/sha.h>
 17 #include <linux/err.h>
 18 #include <linux/module.h>
 19 #include <linux/init.h>
 20 #include <linux/errno.h>
 21 #include <linux/cryptohash.h>
 22 #include <linux/interrupt.h>
 23 #include <linux/kernel.h>
 24 #include <linux/scatterlist.h>
 25 #include <asm/i387.h>
 26 #include "padlock.h"
 27 
 28 #define SHA1_DEFAULT_FALLBACK   "sha1-generic"
 29 #define SHA256_DEFAULT_FALLBACK "sha256-generic"
 30 
 31 struct padlock_sha_ctx {
 32         char            *data;
 33         size_t          used;
 34         int             bypass;
 35         void (*f_sha_padlock)(const char *in, char *out, int count);
 36         struct hash_desc fallback;
 37 };
 38 
 39 static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm)
 40 {
 41         return crypto_tfm_ctx(tfm);
 42 }
 43 
 44 /* We'll need aligned address on the stack */
 45 #define NEAREST_ALIGNED(ptr) \
 46         ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT))
 47 
 48 static struct crypto_alg sha1_alg, sha256_alg;
 49 
 50 static void padlock_sha_bypass(struct crypto_tfm *tfm)
 51 {
 52         if (ctx(tfm)->bypass)
 53                 return;
 54 
 55         crypto_hash_init(&ctx(tfm)->fallback);
 56         if (ctx(tfm)->data && ctx(tfm)->used) {
 57                 struct scatterlist sg;
 58 
 59                 sg_init_one(&sg, ctx(tfm)->data, ctx(tfm)->used);
 60                 crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length);
 61         }
 62 
 63         ctx(tfm)->used = 0;
 64         ctx(tfm)->bypass = 1;
 65 }
 66 
 67 static void padlock_sha_init(struct crypto_tfm *tfm)
 68 {
 69         ctx(tfm)->used = 0;
 70         ctx(tfm)->bypass = 0;
 71 }
 72 
 73 static void padlock_sha_update(struct crypto_tfm *tfm,
 74                         const uint8_t *data, unsigned int length)
 75 {
 76         /* Our buffer is always one page. */
 77         if (unlikely(!ctx(tfm)->bypass &&
 78                      (ctx(tfm)->used + length > PAGE_SIZE)))
 79                 padlock_sha_bypass(tfm);
 80 
 81         if (unlikely(ctx(tfm)->bypass)) {
 82                 struct scatterlist sg;
 83                 sg_init_one(&sg, (uint8_t *)data, length);
 84                 crypto_hash_update(&ctx(tfm)->fallback, &sg, length);
 85                 return;
 86         }
 87 
 88         memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length);
 89         ctx(tfm)->used += length;
 90 }
 91 
 92 static inline void padlock_output_block(uint32_t *src,
 93                         uint32_t *dst, size_t count)
 94 {
 95         while (count--)
 96                 *dst++ = swab32(*src++);
 97 }
 98 
 99 static void padlock_do_sha1(const char *in, char *out, int count)
100 {
101         /* We can't store directly to *out as it may be unaligned. */
102         /* BTW Don't reduce the buffer size below 128 Bytes!
103          *     PadLock microcode needs it that big. */
104         char buf[128+16];
105         char *result = NEAREST_ALIGNED(buf);
106         int ts_state;
107 
108         ((uint32_t *)result)[0] = SHA1_H0;
109         ((uint32_t *)result)[1] = SHA1_H1;
110         ((uint32_t *)result)[2] = SHA1_H2;
111         ((uint32_t *)result)[3] = SHA1_H3;
112         ((uint32_t *)result)[4] = SHA1_H4;
113  
114         /* prevent taking the spurious DNA fault with padlock. */
115         ts_state = irq_ts_save();
116         asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
117                       : "+S"(in), "+D"(result)
118                       : "c"(count), "a"(0));
119         irq_ts_restore(ts_state);
120 
121         padlock_output_block((uint32_t *)result, (uint32_t *)out, 5);
122 }
123 
124 static void padlock_do_sha256(const char *in, char *out, int count)
125 {
126         /* We can't store directly to *out as it may be unaligned. */
127         /* BTW Don't reduce the buffer size below 128 Bytes!
128          *     PadLock microcode needs it that big. */
129         char buf[128+16];
130         char *result = NEAREST_ALIGNED(buf);
131         int ts_state;
132 
133         ((uint32_t *)result)[0] = SHA256_H0;
134         ((uint32_t *)result)[1] = SHA256_H1;
135         ((uint32_t *)result)[2] = SHA256_H2;
136         ((uint32_t *)result)[3] = SHA256_H3;
137         ((uint32_t *)result)[4] = SHA256_H4;
138         ((uint32_t *)result)[5] = SHA256_H5;
139         ((uint32_t *)result)[6] = SHA256_H6;
140         ((uint32_t *)result)[7] = SHA256_H7;
141 
142         /* prevent taking the spurious DNA fault with padlock. */
143         ts_state = irq_ts_save();
144         asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
145                       : "+S"(in), "+D"(result)
146                       : "c"(count), "a"(0));
147         irq_ts_restore(ts_state);
148 
149         padlock_output_block((uint32_t *)result, (uint32_t *)out, 8);
150 }
151 
152 static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out)
153 {
154         if (unlikely(ctx(tfm)->bypass)) {
155                 crypto_hash_final(&ctx(tfm)->fallback, out);
156                 ctx(tfm)->bypass = 0;
157                 return;
158         }
159 
160         /* Pass the input buffer to PadLock microcode... */
161         ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used);
162 
163         ctx(tfm)->used = 0;
164 }
165 
166 static int padlock_cra_init(struct crypto_tfm *tfm)
167 {
168         const char *fallback_driver_name = tfm->__crt_alg->cra_name;
169         struct crypto_hash *fallback_tfm;
170 
171         /* For now we'll allocate one page. This
172          * could eventually be configurable one day. */
173         ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL);
174         if (!ctx(tfm)->data)
175                 return -ENOMEM;
176 
177         /* Allocate a fallback and abort if it failed. */
178         fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
179                                          CRYPTO_ALG_ASYNC |
180                                          CRYPTO_ALG_NEED_FALLBACK);
181         if (IS_ERR(fallback_tfm)) {
182                 printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n",
183                        fallback_driver_name);
184                 free_page((unsigned long)(ctx(tfm)->data));
185                 return PTR_ERR(fallback_tfm);
186         }
187 
188         ctx(tfm)->fallback.tfm = fallback_tfm;
189         return 0;
190 }
191 
192 static int padlock_sha1_cra_init(struct crypto_tfm *tfm)
193 {
194         ctx(tfm)->f_sha_padlock = padlock_do_sha1;
195 
196         return padlock_cra_init(tfm);
197 }
198 
199 static int padlock_sha256_cra_init(struct crypto_tfm *tfm)
200 {
201         ctx(tfm)->f_sha_padlock = padlock_do_sha256;
202 
203         return padlock_cra_init(tfm);
204 }
205 
206 static void padlock_cra_exit(struct crypto_tfm *tfm)
207 {
208         if (ctx(tfm)->data) {
209                 free_page((unsigned long)(ctx(tfm)->data));
210                 ctx(tfm)->data = NULL;
211         }
212 
213         crypto_free_hash(ctx(tfm)->fallback.tfm);
214         ctx(tfm)->fallback.tfm = NULL;
215 }
216 
217 static struct crypto_alg sha1_alg = {
218         .cra_name               =       "sha1",
219         .cra_driver_name        =       "sha1-padlock",
220         .cra_priority           =       PADLOCK_CRA_PRIORITY,
221         .cra_flags              =       CRYPTO_ALG_TYPE_DIGEST |
222                                         CRYPTO_ALG_NEED_FALLBACK,
223         .cra_blocksize          =       SHA1_BLOCK_SIZE,
224         .cra_ctxsize            =       sizeof(struct padlock_sha_ctx),
225         .cra_module             =       THIS_MODULE,
226         .cra_list               =       LIST_HEAD_INIT(sha1_alg.cra_list),
227         .cra_init               =       padlock_sha1_cra_init,
228         .cra_exit               =       padlock_cra_exit,
229         .cra_u                  =       {
230                 .digest = {
231                         .dia_digestsize =       SHA1_DIGEST_SIZE,
232                         .dia_init       =       padlock_sha_init,
233                         .dia_update     =       padlock_sha_update,
234                         .dia_final      =       padlock_sha_final,
235                 }
236         }
237 };
238 
239 static struct crypto_alg sha256_alg = {
240         .cra_name               =       "sha256",
241         .cra_driver_name        =       "sha256-padlock",
242         .cra_priority           =       PADLOCK_CRA_PRIORITY,
243         .cra_flags              =       CRYPTO_ALG_TYPE_DIGEST |
244                                         CRYPTO_ALG_NEED_FALLBACK,
245         .cra_blocksize          =       SHA256_BLOCK_SIZE,
246         .cra_ctxsize            =       sizeof(struct padlock_sha_ctx),
247         .cra_module             =       THIS_MODULE,
248         .cra_list               =       LIST_HEAD_INIT(sha256_alg.cra_list),
249         .cra_init               =       padlock_sha256_cra_init,
250         .cra_exit               =       padlock_cra_exit,
251         .cra_u                  =       {
252                 .digest = {
253                         .dia_digestsize =       SHA256_DIGEST_SIZE,
254                         .dia_init       =       padlock_sha_init,
255                         .dia_update     =       padlock_sha_update,
256                         .dia_final      =       padlock_sha_final,
257                 }
258         }
259 };
260 
261 static int __init padlock_init(void)
262 {
263         int rc = -ENODEV;
264 
265         if (!cpu_has_phe) {
266                 printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n");
267                 return -ENODEV;
268         }
269 
270         if (!cpu_has_phe_enabled) {
271                 printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
272                 return -ENODEV;
273         }
274 
275         rc = crypto_register_alg(&sha1_alg);
276         if (rc)
277                 goto out;
278 
279         rc = crypto_register_alg(&sha256_alg);
280         if (rc)
281                 goto out_unreg1;
282 
283         printk(KERN_NOTICE PFX "Using VIA PadLock ACE for SHA1/SHA256 algorithms.\n");
284 
285         return 0;
286 
287 out_unreg1:
288         crypto_unregister_alg(&sha1_alg);
289 out:
290         printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n");
291         return rc;
292 }
293 
294 static void __exit padlock_fini(void)
295 {
296         crypto_unregister_alg(&sha1_alg);
297         crypto_unregister_alg(&sha256_alg);
298 }
299 
300 module_init(padlock_init);
301 module_exit(padlock_fini);
302 
303 MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
304 MODULE_LICENSE("GPL");
305 MODULE_AUTHOR("Michal Ludvig");
306 
307 MODULE_ALIAS("sha1-all");
308 MODULE_ALIAS("sha256-all");
309 MODULE_ALIAS("sha1-padlock");
310 MODULE_ALIAS("sha256-padlock");
311 
  This page was automatically generated by the LXR engine.