]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/sha/ck_sha_v1.c
Introduce a port for T-HEAD CK802. A simple demo for T-HEAD CB2201 is also included.
[freertos] / FreeRTOS / Demo / T-HEAD_CB2201_CDK / csi / csi_driver / csky / common / sha / ck_sha_v1.c
1 /*
2  * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /******************************************************************************
18  * @file     ck_sha.c
19  * @brief    CSI Source File for SHA Driver
20  * @version  V1.0
21  * @date     02. June 2017
22  ******************************************************************************/
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #include "csi_core.h"
27 #include "drv_sha.h"
28 #include "ck_sha_v1.h"
29
30 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
31 #define CONFIG_SHA_SUPPORT_MUL_THREAD   1
32 #endif
33
34 typedef struct {
35     uint32_t base;
36     uint32_t irq;
37     sha_event_cb_t cb;
38     sha_status_t status;
39     sha_mode_e mode;
40     sha_endian_mode_e endian;
41 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
42     uint32_t  state[16];
43     uint32_t sha_buffer[32];
44     uint32_t total;
45     uint8_t first_cal;
46 #endif
47 } ck_sha_priv_t;
48
49 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
50 static ck_sha_priv_t sha_handle[CONFIG_SHA_NUM];
51 #endif
52 bool finish_flag = 0;
53
54 /* Driver Capabilities */
55 static const sha_capabilities_t driver_capabilities = {
56     .sha1 = 1, /* sha1 mode */
57     .sha224 = 1, /* sha224 mode */
58     .sha256 = 1, /* sha256 mode */
59     .sha384 = 1, /* sha384 mode */
60     .sha512 = 1, /* sha512 mode */
61     .sha512_224 = 1, /* sha512_224 mode */
62     .sha512_256 = 1, /* sha512_256 mode */
63     .endianmode = 1, /* endian mode */
64     .interruptmode = 1  /* interrupt mode */
65 };
66
67 #define ERR_SHA(errno) (CSI_DRV_ERRNO_SHA_BASE | errno)
68 #define SHA_NULL_PARAM_CHK(para)                         \
69         do {                                        \
70             if (para == NULL) {                     \
71                 return ERR_SHA(EDRV_PARAMETER);   \
72             }                                       \
73         } while (0)
74
75 extern int32_t target_get_sha(int32_t idx, uint32_t *base, uint32_t *irq);
76 extern int32_t target_get_sha_count(void);
77 //
78 // Functions
79 //
80
81 ck_sha_reg_t *sha_reg = NULL;
82
83 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
84 static uint32_t sha_buffer[32];
85 static uint32_t total[2] = {0x0};
86 static uint8_t first_cal = 1;
87 #endif
88 static uint8_t sha_result[64] = {0x0};
89
90 static int32_t sha_set_mode(sha_mode_e mode)
91 {
92     sha_reg->SHA_MODE &= ~0x7;
93     sha_reg->SHA_MODE |= mode;
94     return 0;
95 }
96
97 static void sha_set_source_message(uint32_t baseaddr)
98 {
99     sha_reg->SHA_BASEADDR = baseaddr;
100 }
101
102 static void sha_set_dest_message(uint32_t destaddr)
103 {
104     sha_reg->SHA_DESTADDR = destaddr;
105 }
106
107 static void sha_enable_without_count(void)
108 {
109     sha_reg->SHA_MODE |= 1<<25;
110 }
111
112 static void sha_disable_without_count(void)
113 {
114     sha_reg->SHA_MODE &= ~(1<<25);
115 }
116
117 static void sha_set_message_count(uint32_t count)
118 {
119     sha_reg->SHA_COUNTER0 = count;
120     sha_reg->SHA_COUNTER1 = 0;
121 }
122
123 static int32_t sha_enable_initial(void)
124 {
125     sha_reg->SHA_MODE |= 1 << SHA_INIT_OFFSET;
126     return 0;
127 }
128
129 static int32_t sha_disable_initial(void)
130 {
131     sha_reg->SHA_MODE &= ~(1 << SHA_INIT_OFFSET);
132     return 0;
133 }
134
135 static int32_t sha_enable_calculate(void)
136 {
137     sha_reg->SHA_CON |= 1;
138     return 0;
139 }
140
141 static int32_t sha_message_done(void)
142 {
143     while(sha_reg->SHA_CON & 0x1);
144     return 0;
145 }
146
147 static void sha_new_encode(void)
148 {
149     sha_reg->SHA_INTSTATE = 0;
150     sha_reg->SHA_MODE = 0;
151 }
152
153 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
154 static int32_t sha_restore_context(sha_handle_t handle, uint32_t *data)
155 {
156     uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
157
158     uint8_t i;
159     for (i = 0; i < 16; i++) {
160         result[i] = data[i];
161     }
162     return 0;
163 }
164
165 static int32_t sha_save_context(sha_handle_t handle, uint32_t *data)
166 {
167     uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
168
169     uint8_t i;
170     for (i = 0; i < 16; i++) {
171         data[i] = result[i];
172     }
173     return 0;
174 }
175 #endif
176
177 static inline void sha_reverse_order(uint8_t *pdata, int32_t length)
178 {
179     uint8_t input_data[length];
180     uint8_t result[length];
181     uint32_t tmp = 0;
182     int32_t i = 0;
183     memcpy((void *)input_data, (void *)pdata, length);
184
185     for (i = 0; i < length; i++) {
186         tmp = i >> 2;
187         tmp = tmp << 3;
188         result[i] = input_data[tmp + 3 - i];
189     }
190
191     memcpy((void *)pdata, (void *)result, length);
192 }
193
194 /**
195   \brief       get sha handle count.
196   \return      sha handle count
197 */
198 int32_t csi_sha_get_instance_count(void)
199 {
200     return target_get_sha_count();
201 }
202
203 /**
204   \brief       Initialize SHA Interface. 1. Initializes the resources needed for the SHA interface 2.registers event callback function
205   \param[in]   idx must not exceed return value of csi_sha_get_instance_count()
206   \param[in]   cb_event  Pointer to \ref sha_event_cb_t
207   \return      return sha handle if success
208 */
209 sha_handle_t csi_sha_initialize(sha_handle_t handle, sha_event_cb_t cb_event)
210 {
211 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
212     uint32_t base = 0u;
213     uint32_t irq;
214     /* obtain the sha information */
215     target_get_sha(0, &base, &irq);
216     ck_sha_priv_t *sha_priv = handle;
217     memset(sha_priv->state, 0, sizeof(sha_priv->state));
218     sha_priv->total = 0;
219     sha_priv->first_cal = 1;
220
221 #else
222     if (idx < 0 || idx >= CONFIG_SHA_NUM) {
223         return NULL;
224     }
225
226     uint32_t base = 0u;
227     uint32_t irq;
228     /* obtain the sha information */
229     int32_t real_idx = target_get_sha(idx, &base, &irq);
230
231     if (real_idx != idx) {
232         return NULL;
233     }
234     ck_sha_priv_t *sha_priv = &sha_handle[idx];
235 #endif
236     sha_priv->base = base;
237     sha_priv->irq  = irq;
238
239     /* initialize the sha context */
240     sha_priv->cb = cb_event;
241     sha_priv->status.busy = 0;
242
243     return (sha_handle_t)sha_priv;
244 }
245
246 /**
247   \brief       De-initialize SHA Interface. stops operation and releases the software resources used by the interface
248   \param[in]   handle  sha handle to operate.
249   \return      error code
250 */
251 int32_t csi_sha_uninitialize(sha_handle_t handle)
252 {
253     SHA_NULL_PARAM_CHK(handle);
254
255     ck_sha_priv_t *sha_priv = handle;
256     sha_priv->cb = NULL;
257
258     return 0;
259 }
260
261 /**
262   \brief       Get driver capabilities.
263   \param[in]   handle sha handle to operate.
264   \return      \ref sha_capabilities_t
265 */
266 sha_capabilities_t csi_sha_get_capabilities(sha_handle_t handle)
267 {
268     return driver_capabilities;
269 }
270
271 /**
272   \brief       config sha mode.
273   \param[in]   handle  sha handle to operate.
274   \param[in]   mode      \ref sha_mode_e
275   \param[in]   endian    \ref sha_endian_mode_e
276   \return      error code
277 */
278 int32_t csi_sha_config(sha_handle_t handle, sha_mode_e mode, sha_endian_mode_e endian_mode)
279 {
280     SHA_NULL_PARAM_CHK(handle);
281
282     ck_sha_priv_t *sha_priv = handle;
283     sha_reg = (ck_sha_reg_t *)(sha_priv->base);
284
285     /* config the sha mode */
286     switch (mode) {
287         case SHA_MODE_512_256:
288         case SHA_MODE_512_224:
289             return ERR_SHA(EDRV_UNSUPPORTED);
290
291         case SHA_MODE_1:
292         case SHA_MODE_224:
293         case SHA_MODE_256:
294         case SHA_MODE_384:
295         case SHA_MODE_512:
296             sha_priv->mode = mode;
297             break;
298
299         default:
300             return ERR_SHA(EDRV_PARAMETER);
301     }
302
303     return 0;
304 }
305
306 /**
307   \brief       start the engine
308   \param[in]   handle  sha handle to operate.
309   \param[in]   context  Pointer to the sha context.
310   \return      error code
311 */
312 int32_t csi_sha_starts(sha_handle_t handle, void *context)
313 {
314     SHA_NULL_PARAM_CHK(handle);
315
316     ck_sha_priv_t *sha_priv = handle;
317     sha_priv->status.busy = 1;
318
319     sha_new_encode();
320     sha_set_mode(sha_priv->mode);
321
322 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
323     memset(sha_priv->sha_buffer, 0, sizeof(sha_priv->sha_buffer));
324     memset(sha_priv->state, 0, sizeof(sha_priv->state));
325     sha_priv->first_cal = 1;
326     sha_priv->total = 0;
327 #endif
328
329     return 0;
330 }
331
332 /**
333   \brief       updata the engine
334   \param[in]   handle  sha handle to operate.
335   \param[in]   context  Pointer to the sha context.
336   \param[in]   input   Pointer to the Source data
337   \param[in]   len    the data len
338   \return      error code
339 */
340 int32_t csi_sha_update(sha_handle_t handle, void *context, const void *input, uint32_t len)
341 {
342     SHA_NULL_PARAM_CHK(handle);
343     SHA_NULL_PARAM_CHK(input);
344     if (len <= 0) {
345         return ERR_SHA(EDRV_PARAMETER);
346     }
347
348     ck_sha_priv_t *sha_priv = handle;
349     sha_reg = (ck_sha_reg_t *)(sha_priv->base);
350
351     uint8_t total_len_num;
352     uint32_t block_size;
353     if (sha_priv->mode < 4) {
354         block_size = 64;
355         total_len_num = 2;
356     } else {
357         block_size = 128;
358         total_len_num = 4;
359     }
360
361 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
362     uint32_t *sha_buffer = sha_priv->sha_buffer;
363     uint8_t first_cal = sha_priv->first_cal;
364     sha_set_mode(sha_priv->mode);
365     uint32_t left = sha_priv->total & (block_size - 1);
366     uint32_t fill = block_size - left;
367     uint32_t total_length = sha_priv->total << 3;
368     uint32_t index = left >> 2;
369
370     if (left & 0x3) {
371         index++;
372     }
373     sha_priv->total += len;
374     sha_priv->total &= 0xffffffff;
375 #else
376     uint32_t left = total[0] & (block_size - 1);
377     uint32_t fill = block_size - left;
378     uint32_t total_length = total[0] << 3;
379     uint32_t index = left >> 2;
380
381     if (left & 0x3) {
382         index++;
383     }
384     total[0] += len;
385     total[0] &= 0xffffffff;
386 #endif
387     uint8_t *p = (uint8_t *)input;
388     /* when the text is not aligned by block and len > fill */
389     if (left && len >= fill) {
390         if (finish_flag) {
391 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
392             memset(((uint8_t *)sha_buffer + left), 0x0, sizeof(sha_priv->sha_buffer) - left);
393 #else
394             memset(((uint8_t *)sha_buffer + left), 0x0, sizeof(sha_buffer) - left);
395 #endif
396             sha_buffer[index + total_len_num - 1] = total_length;
397
398             sha_disable_without_count();
399             sha_set_message_count(left << 3);
400         } else {
401             memcpy((void *)(((uint8_t *)sha_buffer) + left), p, fill);
402             p += fill;
403
404             sha_enable_without_count();
405             sha_set_message_count(block_size << 3);
406         }
407
408         sha_set_source_message((uint32_t)sha_buffer);
409         sha_set_dest_message((uint32_t)sha_result);
410         if (first_cal == 0) {
411             sha_enable_initial();
412         } else {
413             sha_disable_initial();
414         }
415
416 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
417         sha_restore_context(handle, (uint32_t *)sha_priv->state);
418 #endif
419
420         sha_enable_calculate();
421         sha_message_done();
422
423 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
424         sha_save_context(handle, (uint32_t *)sha_priv->state);
425 #endif
426         len -= fill;
427         left = 0;
428 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
429         sha_priv->first_cal = 0;
430         first_cal = 0;
431 #else
432         first_cal = 0;
433 #endif
434     }
435
436     /* calculate the hash by block */
437     while (len >= block_size) {
438         if (finish_flag) {
439 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
440             memset(sha_buffer, 0, sizeof(sha_priv->sha_buffer));
441 #else
442             memset(sha_buffer, 0, sizeof(sha_buffer));
443 #endif
444             sha_buffer[total_len_num - 1] = total_length;
445
446             sha_set_source_message((uint32_t)sha_buffer);
447             sha_disable_without_count();
448             sha_set_message_count(0);
449         } else {
450             memcpy(sha_buffer, p, block_size);
451             sha_set_source_message((uint32_t)sha_buffer);
452             sha_enable_without_count();
453             sha_set_message_count(block_size << 3);
454             p += block_size;
455         }
456         sha_set_dest_message((uint32_t)sha_result);
457         if (first_cal == 0) {
458             sha_enable_initial();
459         } else {
460             sha_disable_initial();
461         }
462 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
463         sha_restore_context(handle, (uint32_t *)sha_priv->state);
464 #endif
465
466         sha_enable_calculate();
467         sha_message_done();
468 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
469         sha_save_context(handle, (uint32_t *)sha_priv->state);
470 #endif
471 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
472         sha_priv->first_cal = 0;
473         first_cal = 0;
474 #else
475         first_cal = 0;
476 #endif
477         len -= block_size;
478     }
479
480     /* when the text is not aligned by block and len < fill */
481     if (len > 0) {
482         memcpy((void *)(((uint8_t *)sha_buffer) + left), p, len);
483     }
484
485     sha_priv->status.busy = 0;
486
487     return 0;
488 }
489
490 /**
491   \brief       finish the engine
492   \param[in]   handle  sha handle to operate.
493   \param[in]   context  Pointer to the sha context.
494   \param[out]  output   Pointer to the dest data
495   \return      error code
496 */
497 int32_t csi_sha_finish(sha_handle_t handle, void *context, void *output)
498 {
499     SHA_NULL_PARAM_CHK(handle);
500     SHA_NULL_PARAM_CHK(output);
501
502     ck_sha_priv_t *sha_priv = handle;
503     uint32_t block_size;
504     if (sha_priv->mode < 4) {
505         block_size = 64;
506     } else {
507         block_size = 128;
508     }
509
510 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
511     uint32_t last = sha_priv->total & (block_size - 1);
512 #else
513     uint32_t last = total[0] & (block_size - 1);
514 #endif
515     uint32_t padn = block_size - last;
516
517     finish_flag = 1;
518
519     csi_sha_update(handle, NULL, output, padn);
520
521     uint8_t result_len = 20;
522     /* convert the data endian according the sha mode */
523     if (sha_priv->mode == SHA_MODE_1) {
524         result_len = 20;
525     } else if (sha_priv->mode == SHA_MODE_224) {
526         result_len = 28;
527     } else if (sha_priv->mode == SHA_MODE_256) {
528         result_len = 32;
529     } else if (sha_priv->mode == SHA_MODE_512) {
530         result_len = 64;
531     } else if (sha_priv->mode == SHA_MODE_384) {
532         result_len = 48;
533     }
534     sha_reverse_order(sha_result, result_len);
535     memcpy((uint8_t*)output, sha_result, result_len);
536
537     finish_flag = 0;
538 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
539     memset(sha_priv->sha_buffer, 0, sizeof(sha_priv->sha_buffer));
540     sha_priv->first_cal = 1;
541     sha_priv->total = 0;
542 #else
543     memset(sha_buffer, 0, sizeof(sha_buffer));
544     first_cal = 1;
545     total[0] = 0;
546 #endif
547     return 0;
548 }
549
550 /**
551   \brief       Get SHA status.
552   \param[in]   handle  sha handle to operate.
553   \return      SHA status \ref sha_status_t
554 */
555 sha_status_t csi_sha_get_status(sha_handle_t handle)
556 {
557     ck_sha_priv_t *sha_priv = handle;
558     return sha_priv->status;
559 }