2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
16 * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
17 * Copyright (C) 2009 Mohammad Firdaus
21 \defgroup IFX_DEU IFX_DEU_DRIVERS
23 \brief ifx deu driver module
29 \brief ARC4 encryption DEU driver file
33 \defgroup IFX_ARC4_FUNCTIONS IFX_ARC4_FUNCTIONS
35 \brief IFX deu driver functions
39 #include <linux/version.h>
40 #include <linux/module.h>
41 #include <linux/init.h>
42 #include <linux/types.h>
43 #include <linux/errno.h>
44 #include <linux/crypto.h>
45 #include <crypto/algapi.h>
46 #include <linux/interrupt.h>
47 #include <asm/byteorder.h>
48 #include <linux/delay.h>
49 #include "ifxmips_deu.h"
51 #ifdef CONFIG_CRYPTO_DEV_IFXMIPS_DMA
53 static spinlock_t lock
;
54 #define CRTCL_SECT_INIT spin_lock_init(&lock)
55 #define CRTCL_SECT_START spin_lock_irqsave(&lock, flag)
56 #define CRTCL_SECT_END spin_unlock_irqrestore(&lock, flag)
58 /* Preprocessor declerations */
59 #define ARC4_MIN_KEY_SIZE 1
60 //#define ARC4_MAX_KEY_SIZE 256
61 #define ARC4_MAX_KEY_SIZE 16
62 #define ARC4_BLOCK_SIZE 1
63 #define ARC4_START IFX_ARC4_CON
66 * \brief arc4 private structure
73 extern int disable_deudma
;
75 /*! \fn static void _deu_arc4 (void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
76 \ingroup IFX_ARC4_FUNCTIONS
77 \brief main interface to AES hardware
78 \param ctx_arg crypto algo context
79 \param out_arg output bytestream
80 \param in_arg input bytestream
81 \param iv_arg initialization vector
82 \param nbytes length of bytestream
83 \param encdec 1 for encrypt; 0 for decrypt
84 \param mode operation mode such as ebc, cbc, ctr
86 static void _deu_arc4 (void *ctx_arg
, u8
*out_arg
, const u8
*in_arg
,
87 u8
*iv_arg
, u32 nbytes
, int encdec
, int mode
)
89 volatile struct arc4_t
*arc4
= (struct arc4_t
*) ARC4_START
;
93 #if 1 // need to handle nbytes not multiple of 16
94 volatile u32 tmp_array32
[4];
95 volatile u8
*tmp_ptr8
;
96 int remaining_bytes
, j
;
101 arc4
->IDLEN
= nbytes
;
105 arc4
->ID3R
= *((u32
*) in_arg
+ (i
>>2) + 0);
106 arc4
->ID2R
= *((u32
*) in_arg
+ (i
>>2) + 1);
107 arc4
->ID1R
= *((u32
*) in_arg
+ (i
>>2) + 2);
108 arc4
->ID0R
= *((u32
*) in_arg
+ (i
>>2) + 3);
110 arc4
->controlr
.GO
= 1;
112 while (arc4
->controlr
.BUS
) {
113 // this will not take long
117 // need to handle nbytes not multiple of 16
118 tmp_array32
[0] = arc4
->OD3R
;
119 tmp_array32
[1] = arc4
->OD2R
;
120 tmp_array32
[2] = arc4
->OD1R
;
121 tmp_array32
[3] = arc4
->OD0R
;
123 remaining_bytes
= nbytes
- i
;
124 if (remaining_bytes
> 16)
125 remaining_bytes
= 16;
127 tmp_ptr8
= (u8
*)&tmp_array32
[0];
128 for (j
= 0; j
< remaining_bytes
; j
++)
129 *out_arg
++ = *tmp_ptr8
++;
131 *((u32
*) out_arg
+ (i
>>2) + 0) = arc4
->OD3R
;
132 *((u32
*) out_arg
+ (i
>>2) + 1) = arc4
->OD2R
;
133 *((u32
*) out_arg
+ (i
>>2) + 2) = arc4
->OD1R
;
134 *((u32
*) out_arg
+ (i
>>2) + 3) = arc4
->OD0R
;
147 /*! \fn arc4_chip_init (void)
148 \ingroup IFX_ARC4_FUNCTIONS
149 \brief initialize arc4 hardware
151 static void arc4_chip_init (void)
156 /*! \fn static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len)
157 \ingroup IFX_ARC4_FUNCTIONS
159 \param tfm linux crypto algo transform
160 \param in_key input key
161 \param key_len key lengths less than or equal to 16 bytes supported
163 static int arc4_set_key(struct crypto_tfm
*tfm
, const u8
*inkey
,
164 unsigned int key_len
)
166 //struct arc4_ctx *ctx = crypto_tfm_ctx(tfm);
167 volatile struct arc4_t
*arc4
= (struct arc4_t
*) ARC4_START
;
169 u32
*in_key
= (u32
*)inkey
;
171 // must program all bits at one go?!!!
173 //#ifndef CONFIG_CRYPTO_DEV_VR9_DMA
174 *IFX_ARC4_CON
= ( (1<<31) | ((key_len
- 1)<<27) | (1<<26) | (3<<16) );
175 //NDC=1,ENDI=1,GO=0,KSAE=1,SM=0
177 arc4
->K3R
= *((u32
*) in_key
+ 0);
178 arc4
->K2R
= *((u32
*) in_key
+ 1);
179 arc4
->K1R
= *((u32
*) in_key
+ 2);
180 arc4
->K0R
= *((u32
*) in_key
+ 3);
182 *AMAZONS_ARC4_CON
= ( (1<<31) | ((key_len
- 1)<<27) | (1<<26) | (3<<16) | (1<<4) );
183 //NDC=1,ENDI=1,GO=0,KSAE=1,SM=1
185 arc4
->K3R
= *((u32
*) in_key
+ 0);
186 arc4
->K2R
= *((u32
*) in_key
+ 1);
187 arc4
->K1R
= *((u32
*) in_key
+ 2);
188 arc4
->K0R
= *((u32
*) in_key
+ 3);
191 arc4
->K3R
= endian_swap(*((u32
*) in_key
+ 0));
192 arc4
->K2R
= endian_swap(*((u32
*) in_key
+ 1));
193 arc4
->K1R
= endian_swap(*((u32
*) in_key
+ 2));
194 arc4
->K0R
= endian_swap(*((u32
*) in_key
+ 3));
199 #if 0 // arc4 is a ugly state machine, KSAE can only be set once per session
200 ctx
->key_length
= key_len
;
202 memcpy ((u8
*) (ctx
->buf
), in_key
, key_len
);
208 /*! \fn static void _deu_arc4_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
209 \ingroup IFX_ARC4_FUNCTIONS
210 \brief sets ARC4 hardware to ECB mode
211 \param ctx crypto algo context
212 \param dst output bytestream
213 \param src input bytestream
214 \param iv initialization vector
215 \param nbytes length of bytestream
216 \param encdec 1 for encrypt; 0 for decrypt
217 \param inplace not used
219 static void _deu_arc4_ecb(void *ctx
, uint8_t *dst
, const uint8_t *src
,
220 uint8_t *iv
, size_t nbytes
, int encdec
, int inplace
)
222 _deu_arc4 (ctx
, dst
, src
, NULL
, nbytes
, encdec
, 0);
225 /*! \fn static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
226 \ingroup IFX_ARC4_FUNCTIONS
227 \brief encrypt/decrypt ARC4_BLOCK_SIZE of data
228 \param tfm linux crypto algo transform
229 \param out output bytestream
230 \param in input bytestream
232 static void arc4_crypt(struct crypto_tfm
*tfm
, u8
*out
, const u8
*in
)
234 struct arc4_ctx
*ctx
= crypto_tfm_ctx(tfm
);
236 _deu_arc4 (ctx
, out
, in
, NULL
, ARC4_BLOCK_SIZE
,
237 CRYPTO_DIR_DECRYPT
, CRYPTO_TFM_MODE_ECB
);
242 * \brief ARC4 function mappings
244 static struct crypto_alg ifxdeu_arc4_alg
= {
246 .cra_driver_name
= "ifxdeu-arc4",
247 .cra_flags
= CRYPTO_ALG_TYPE_CIPHER
,
248 .cra_blocksize
= ARC4_BLOCK_SIZE
,
249 .cra_ctxsize
= sizeof(struct arc4_ctx
),
250 .cra_module
= THIS_MODULE
,
251 .cra_list
= LIST_HEAD_INIT(ifxdeu_arc4_alg
.cra_list
),
254 .cia_min_keysize
= ARC4_MIN_KEY_SIZE
,
255 .cia_max_keysize
= ARC4_MAX_KEY_SIZE
,
256 .cia_setkey
= arc4_set_key
,
257 .cia_encrypt
= arc4_crypt
,
258 .cia_decrypt
= arc4_crypt
,
263 /*! \fn static int ecb_arc4_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
264 \ingroup IFX_ARC4_FUNCTIONS
265 \brief ECB ARC4 encrypt using linux crypto blkcipher
266 \param desc blkcipher descriptor
267 \param dst output scatterlist
268 \param src input scatterlist
269 \param nbytes data size in bytes
271 static int ecb_arc4_encrypt(struct blkcipher_desc
*desc
,
272 struct scatterlist
*dst
, struct scatterlist
*src
,
275 struct arc4_ctx
*ctx
= crypto_blkcipher_ctx(desc
->tfm
);
276 struct blkcipher_walk walk
;
280 blkcipher_walk_init(&walk
, dst
, src
, nbytes
);
281 err
= blkcipher_walk_virt(desc
, &walk
);
283 while ((nbytes
= walk
.nbytes
)) {
284 _deu_arc4_ecb(ctx
, walk
.dst
.virt
.addr
, walk
.src
.virt
.addr
,
285 NULL
, nbytes
, CRYPTO_DIR_ENCRYPT
, 0);
286 nbytes
&= ARC4_BLOCK_SIZE
- 1;
287 err
= blkcipher_walk_done(desc
, &walk
, nbytes
);
293 /*! \fn static int ecb_arc4_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
294 \ingroup IFX_ARC4_FUNCTIONS
295 \brief ECB ARC4 decrypt using linux crypto blkcipher
296 \param desc blkcipher descriptor
297 \param dst output scatterlist
298 \param src input scatterlist
299 \param nbytes data size in bytes
301 static int ecb_arc4_decrypt(struct blkcipher_desc
*desc
,
302 struct scatterlist
*dst
, struct scatterlist
*src
,
305 struct arc4_ctx
*ctx
= crypto_blkcipher_ctx(desc
->tfm
);
306 struct blkcipher_walk walk
;
310 blkcipher_walk_init(&walk
, dst
, src
, nbytes
);
311 err
= blkcipher_walk_virt(desc
, &walk
);
313 while ((nbytes
= walk
.nbytes
)) {
314 _deu_arc4_ecb(ctx
, walk
.dst
.virt
.addr
, walk
.src
.virt
.addr
,
315 NULL
, nbytes
, CRYPTO_DIR_DECRYPT
, 0);
316 nbytes
&= ARC4_BLOCK_SIZE
- 1;
317 err
= blkcipher_walk_done(desc
, &walk
, nbytes
);
324 * \brief ARC4 function mappings
326 static struct crypto_alg ifxdeu_ecb_arc4_alg
= {
327 .cra_name
= "ecb(arc4)",
328 .cra_driver_name
= "ifxdeu-ecb(arc4)",
329 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
330 .cra_blocksize
= ARC4_BLOCK_SIZE
,
331 .cra_ctxsize
= sizeof(struct arc4_ctx
),
332 .cra_type
= &crypto_blkcipher_type
,
333 .cra_module
= THIS_MODULE
,
334 .cra_list
= LIST_HEAD_INIT(ifxdeu_ecb_arc4_alg
.cra_list
),
337 .min_keysize
= ARC4_MIN_KEY_SIZE
,
338 .max_keysize
= ARC4_MAX_KEY_SIZE
,
339 .setkey
= arc4_set_key
,
340 .encrypt
= ecb_arc4_encrypt
,
341 .decrypt
= ecb_arc4_decrypt
,
346 /*! \fn int __init ifxdeu_init_arc4(void)
347 \ingroup IFX_ARC4_FUNCTIONS
348 \brief initialize arc4 driver
350 int __init
ifxdeu_init_arc4(void)
354 if ((ret
= crypto_register_alg(&ifxdeu_arc4_alg
)))
357 if ((ret
= crypto_register_alg(&ifxdeu_ecb_arc4_alg
)))
364 printk (KERN_NOTICE
"IFX DEU ARC4 initialized %s.\n", disable_deudma
? "" : " (DMA)");
368 crypto_unregister_alg(&ifxdeu_arc4_alg
);
369 printk(KERN_ERR
"IFX arc4 initialization failed!\n");
372 crypto_unregister_alg(&ifxdeu_ecb_arc4_alg
);
373 printk (KERN_ERR
"IFX ecb_arc4 initialization failed!\n");
378 /*! \fn void __exit ifxdeu_fini_arc4(void)
379 \ingroup IFX_ARC4_FUNCTIONS
380 \brief unregister arc4 driver
382 void __exit
ifxdeu_fini_arc4(void)
384 crypto_unregister_alg (&ifxdeu_arc4_alg
);
385 crypto_unregister_alg (&ifxdeu_ecb_arc4_alg
);