2 * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /******************************************************************************
19 * @brief CSI Source File for SHA Driver
22 ******************************************************************************/
28 #include "ck_sha_v2.h"
30 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
31 #define CONFIG_SHA_SUPPORT_MUL_THREAD 1
40 sha_endian_mode_e endian;
41 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
43 uint8_t sha_buffer[128];
49 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
50 static ck_sha_priv_t sha_handle[CONFIG_SHA_NUM];
52 static uint32_t g_sha_context[CONFIG_SHA_NUM];
55 /* Driver Capabilities */
56 static const sha_capabilities_t driver_capabilities = {
57 .sha1 = 1, /* sha1 mode */
58 .sha224 = 1, /* sha224 mode */
59 .sha256 = 1, /* sha256 mode */
60 .sha384 = 1, /* sha384 mode */
61 .sha512 = 1, /* sha512 mode */
62 .sha512_224 = 1, /* sha512_224 mode */
63 .sha512_256 = 1, /* sha512_256 mode */
64 .endianmode = 1, /* endian mode */
65 .interruptmode = 1 /* interrupt mode */
68 #define ERR_SHA(errno) (CSI_DRV_ERRNO_SHA_BASE | errno)
69 #define SHA_NULL_PARAM_CHK(para) \
72 return ERR_SHA(EDRV_PARAMETER); \
79 ck_sha_reg_t *sha_reg = NULL;
80 volatile static uint8_t sha_int_flag = 1;
82 extern int32_t target_get_sha_count(void);
83 extern int32_t target_get_sha(int32_t idx, uint32_t *base, uint32_t *irq);
85 static int32_t sha_set_mode(sha_mode_e mode)
87 sha_reg->SHA_CON &= ~0x7;
88 sha_reg->SHA_CON |= mode;
92 #ifndef CONFIG_SHA_BLOCK_MODE
93 static int32_t sha_enable_interrupt(void)
95 sha_reg->SHA_CON |= 1 << SHA_INT_ENABLE_OFFSET;
99 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
100 static int32_t sha_disable_interrupt(void)
102 sha_reg->SHA_CON &= ~(1 << SHA_INT_ENABLE_OFFSET);
108 static void sha_clear_interrupt(void)
110 sha_reg->SHA_INTSTATE = 0;
113 static int32_t sha_enable_initial(void)
115 sha_reg->SHA_CON |= 1 << SHA_INIT_OFFSET;
119 static int32_t sha_enable_calculate(void)
121 sha_reg->SHA_CON |= 1 << SHA_CAL_OFFSET;
125 #ifdef CONFIG_SHA_BLOCK_MODE
126 static int32_t sha_message_done(void)
128 while((sha_reg->SHA_CON & 0x40));
133 static int32_t sha_select_endian_mode(sha_endian_mode_e mode)
135 sha_reg->SHA_CON &= ~(1 << SHA_ENDIAN_OFFSET);
136 sha_reg->SHA_CON |= mode << SHA_ENDIAN_OFFSET;
140 static int32_t sha_input_data(uint32_t *data, uint32_t length)
144 uint32_t *input_data = (uint32_t *) & (sha_reg->SHA_DATA1);
146 for (i = 0; i < length; i++) {
147 memcpy(&tmp, (uint8_t *)(data+i), 4);
148 *(input_data + i) = tmp;
154 static int32_t sha_get_data(sha_handle_t handle, uint32_t *data)
156 ck_sha_priv_t *sha_priv = handle;
161 uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
162 /* according to different mode to obtain the hash result */
163 if (sha_priv->mode == SHA_MODE_1 || sha_priv->mode == SHA_MODE_224 || sha_priv->mode == SHA_MODE_256) {
164 if (sha_priv->mode == SHA_MODE_1) {
166 } else if (sha_priv->mode == SHA_MODE_224) {
168 } else if (sha_priv->mode == SHA_MODE_256) {
172 for (i = 0; i < len; i++) {
173 temp = *(result + i);
174 memcpy(&data[i], &temp, 4);
177 if (sha_priv->mode == SHA_MODE_384) {
179 } else if (sha_priv->mode == SHA_MODE_512) {
183 uint32_t *resulth = (uint32_t *)&sha_reg->SHA_H0H;
184 for (i = 0; i < len; i++) {
185 // data[i << 1] = *(resulth + i);
186 // data[(i << 1) + 1] = *(result + i);
187 temp = *(resulth + i);
188 memcpy(&data[i<<1], &temp, 4);
189 temp = *(result + i);
190 memcpy(&data[(i<<1)+1], &temp, 4);
197 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
198 static int32_t sha_set_data(sha_handle_t handle, uint32_t *data)
200 ck_sha_priv_t *sha_priv = handle;
204 uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
205 /* according to different mode to obtain the hash result */
206 if (sha_priv->mode == SHA_MODE_1 || sha_priv->mode == SHA_MODE_224 || sha_priv->mode == SHA_MODE_256) {
207 if (sha_priv->mode == SHA_MODE_1) {
209 } else if (sha_priv->mode == SHA_MODE_224) {
211 } else if (sha_priv->mode == SHA_MODE_256) {
215 for (i = 0; i < len; i++) {
216 *(result + i) = data[i];
219 if (sha_priv->mode == SHA_MODE_384) {
221 } else if (sha_priv->mode == SHA_MODE_512) {
225 uint32_t *resulth = (uint32_t *)&sha_reg->SHA_H0H;
226 for (i = 0; i < len; i++) {
227 *(resulth + i) = data[i << 1];
228 *(result + i) = data[(i << 1) + 1] ;
236 static inline void sha_reverse_order(uint8_t *pdata, int32_t length)
238 uint8_t input_data[length];
239 uint8_t result[length];
242 memcpy((void *)input_data, (void *)pdata, length);
244 for (i = 0; i < length; i++) {
247 result[i] = input_data[tmp + 3 - i];
250 memcpy((void *)pdata, (void *)result, length);
253 void ck_sha_irqhandler(int32_t idx)
256 sha_clear_interrupt(); //clear sha interrupt
258 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
259 ck_sha_priv_t *sha_priv = &sha_handle[idx];
261 ck_sha_priv_t *sha_priv = (ck_sha_priv_t *)g_sha_context[idx];
263 if (finish_flag != 0) {
264 if (sha_priv->cb != NULL) {
265 sha_priv->cb(SHA_EVENT_COMPLETE); //execute the callback function
271 \brief get sha handle count.
272 \return sha handle count
274 int32_t csi_sha_get_instance_count(void)
276 return target_get_sha_count();
280 \brief Initialize SHA Interface. 1. Initializes the resources needed for the SHA interface 2.registers event callback function
281 \param[in] idx must not exceed return value of csi_sha_get_instance_count()
282 \param[in] cb_event Pointer to \ref sha_event_cb_t
283 \return return sha handle if success
285 sha_handle_t csi_sha_initialize(sha_handle_t handle, sha_event_cb_t cb_event)
288 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
291 /* obtain the sha information */
292 target_get_sha(0, &base, &irq);
293 ck_sha_priv_t *sha_priv = handle;
294 memset(sha_priv->state, 0, sizeof(sha_priv->state));
295 sha_priv->last_left = 0;
297 g_sha_context[0] = (uint32_t)handle;
299 if (idx < 0 || idx >= CONFIG_SHA_NUM) {
305 /* obtain the sha information */
306 int32_t real_idx = target_get_sha(idx, &base, &irq);
308 if (real_idx != idx) {
311 ck_sha_priv_t *sha_priv = &sha_handle[idx];
313 sha_priv->base = base;
316 /* initialize the sha context */
317 sha_priv->cb = cb_event;
318 sha_priv->status.busy = 0;
320 #ifndef CONFIG_SHA_BLOCK_MODE
321 drv_nvic_enable_irq(sha_priv->irq);
324 return (sha_handle_t)sha_priv;
328 \brief De-initialize SHA Interface. stops operation and releases the software resources used by the interface
329 \param[in] handle sha handle to operate.
332 int32_t csi_sha_uninitialize(sha_handle_t handle)
334 SHA_NULL_PARAM_CHK(handle);
336 ck_sha_priv_t *sha_priv = handle;
339 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
340 #ifndef CONFIG_SHA_BLOCK_MODE
341 sha_disable_interrupt();
342 drv_nvic_disable_irq(sha_priv->irq);
350 \brief Get driver capabilities.
351 \param[in] handle sha handle to operate.
352 \return \ref sha_capabilities_t
354 sha_capabilities_t csi_sha_get_capabilities(sha_handle_t handle)
356 return driver_capabilities;
360 \brief config sha mode.
361 \param[in] handle sha handle to operate.
362 \param[in] mode \ref sha_mode_e
363 \param[in] endian \ref sha_endian_mode_e
366 int32_t csi_sha_config(sha_handle_t handle, sha_mode_e mode, sha_endian_mode_e endian_mode)
368 SHA_NULL_PARAM_CHK(handle);
370 ck_sha_priv_t *sha_priv = handle;
371 sha_reg = (ck_sha_reg_t *)(sha_priv->base);
373 /* config the sha mode */
375 case SHA_MODE_512_256:
376 case SHA_MODE_512_224:
377 return ERR_SHA(EDRV_UNSUPPORTED);
384 sha_priv->mode = mode;
388 return ERR_SHA(EDRV_PARAMETER);
393 /*config the sha endian mode */
394 if (endian_mode == SHA_ENDIAN_MODE_LITTLE) {
395 sha_priv->endian = endian_mode;
396 sha_select_endian_mode(endian_mode);
397 } else if (endian_mode == SHA_ENDIAN_MODE_BIG) {
398 sha_priv->endian = endian_mode;
399 sha_select_endian_mode(endian_mode);
401 return ERR_SHA(EDRV_PARAMETER);
404 #ifndef CONFIG_SHA_BLOCK_MODE
405 sha_enable_interrupt();
412 \brief start the engine
413 \param[in] handle sha handle to operate.
414 \param[in] context Pointer to the sha context.
417 int32_t csi_sha_starts(sha_handle_t handle, void *context)
419 SHA_NULL_PARAM_CHK(handle);
421 ck_sha_priv_t *sha_priv = handle;
422 sha_enable_initial();
423 sha_priv->status.busy = 1;
425 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
426 sha_get_data(handle, (uint32_t *)sha_priv->state);
433 \brief updata the engine
434 \param[in] handle sha handle to operate.
435 \param[in] context Pointer to the sha context.
436 \param[in] input Pointer to the Source data
437 \param[in] len the data len
440 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
441 static uint8_t sha_buffer[128];
442 static uint32_t total[2] = {0x0};
443 static uint32_t last_left = 0;
445 int32_t csi_sha_update(sha_handle_t handle, void *context, const void *input, uint32_t len)
447 SHA_NULL_PARAM_CHK(handle);
448 SHA_NULL_PARAM_CHK(input);
450 return ERR_SHA(EDRV_PARAMETER);
452 g_sha_context[0] = (uint32_t)handle;
453 ck_sha_priv_t *sha_priv = handle;
454 sha_reg = (ck_sha_reg_t *)(sha_priv->base);
457 if (sha_priv->mode < 4) {
463 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
464 uint8_t *sha_buffer = sha_priv->sha_buffer;
465 uint32_t last_left = sha_priv->last_left;
466 sha_set_mode(sha_priv->mode);
467 uint32_t left = sha_priv->total & (block_size - 1);
468 uint32_t fill = block_size - left;
469 uint32_t total_length = sha_priv->total << 3;
471 sha_priv->total += len;
472 sha_priv->total &= 0xffffffff;
473 uint32_t word_left = sha_priv->total & 0x3;
475 uint32_t left = total[0] & (block_size - 1);
476 uint32_t fill = block_size - left;
477 uint32_t total_length = total[0] << 3;
480 total[0] &= 0xffffffff;
481 uint32_t word_left = total[0] & 0x3;
483 uint8_t temp_data[4];
486 /*calculate the final word*/
487 for (j = 0; j < 4; j++) {
488 temp_data[j] = (total_length >> (8 * j)) & 0xff;
492 uint8_t *p = (uint8_t *)input;
493 /* when the text is not aligned by block and len > fill */
494 if (left && len >= fill) {
496 if (sha_priv->endian == SHA_ENDIAN_MODE_BIG) {
497 memset(&sha_buffer[left], 0x0, len);
498 sha_buffer[left] = 0x80;
499 for (j=0; j<4; j++) {
500 sha_buffer[left + len - 4 + j] = temp_data[3 - j];
503 memset(&sha_buffer[left + 4 - last_left], 0x0, len - 4 + last_left);
504 sha_buffer[left - last_left + 3 - last_left] = 0x80;
505 for (j = 1; j < 4 - last_left; j++) {
506 sha_buffer[left - last_left + 3 - last_left - j] = 0x00;
508 for (j=0; j<4; j++) {
509 sha_buffer[left + len - 4 + j] = temp_data[j];
513 if (last_left && sha_priv->endian == SHA_ENDIAN_MODE_LITTLE) {
515 for (i = 0; i < 4 - last_left; i++) {
516 *(sha_buffer + left + 3 - last_left - i) = *((uint8_t *)p + 3 - last_left - i);
519 fill = fill - 4 + last_left;
520 p = (p + 4 - last_left);
522 else if (last_left) {
523 memcpy((void *)(sha_buffer + left + 4 - last_left), p, fill);
525 memcpy((void *)(sha_buffer + left), p, fill);
530 /* set the input data */
531 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
532 sha_set_data(handle, (uint32_t *)sha_priv->state);
534 sha_input_data((uint32_t *)sha_buffer, block_size >> 2);
535 sha_enable_calculate();
537 #ifdef CONFIG_SHA_BLOCK_MODE
541 while (sha_int_flag);
546 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
547 sha_get_data(handle, (uint32_t *)sha_priv->state);
553 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
554 memset(sha_buffer, 0, sizeof(sha_priv->sha_buffer));
556 memset(sha_buffer, 0, sizeof(sha_buffer));
558 if (sha_priv->endian == SHA_ENDIAN_MODE_BIG) {
559 sha_buffer[0] = 0x80;
560 for (j = 0; j < 4; j++) {
561 sha_buffer[block_size - 4 + j] = temp_data[3 - j];
564 sha_buffer[3 - last_left] = 0x80;
565 for (j = 0; j < 4; j++) {
566 sha_buffer[block_size - 4 + j] = temp_data[j];
572 /* calculate the hash by block */
573 while (len >= block_size) {
574 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
575 sha_set_data(handle, (uint32_t *)sha_priv->state);
578 if (fill == block_size) {
579 sha_input_data((uint32_t *)sha_buffer, block_size >> 2);
581 sha_input_data((uint32_t *)&sha_buffer[block_size], block_size >> 2);
585 sha_input_data((uint32_t *)p, block_size >> 2);
588 sha_enable_calculate();
590 #ifdef CONFIG_SHA_BLOCK_MODE
594 while (sha_int_flag);
599 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
600 sha_get_data(handle, (uint32_t *)sha_priv->state);
605 /* when the text is not aligned by block and len < fill */
607 if (sha_priv->endian == SHA_ENDIAN_MODE_BIG || word_left == 0) {
608 memcpy((void *)(sha_buffer + left), p, len);
610 memcpy((void *)(sha_buffer + left), p, len + 4 - word_left);
611 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
612 sha_priv->last_left = word_left;
614 last_left = word_left;
619 sha_priv->status.busy = 0;
625 \brief finish the engine
626 \param[in] handle sha handle to operate.
627 \param[in] context Pointer to the sha context.
628 \param[out] output Pointer to the dest data
631 //static uint32_t total_length;
632 int32_t csi_sha_finish(sha_handle_t handle, void *context, void *output)
634 SHA_NULL_PARAM_CHK(handle);
635 SHA_NULL_PARAM_CHK(output);
637 ck_sha_priv_t *sha_priv = handle;
640 if (sha_priv->mode < 4) {
648 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
649 uint32_t last = sha_priv->total & (block_size - 1);
650 uint32_t padn = (last < (block_size - message_len)) ? (block_size - last) : (block_size + block_size - last);
653 uint32_t last = total[0] & (block_size - 1);
654 uint32_t padn = (last < (block_size - message_len)) ? (block_size - last) : (block_size + block_size - last);
660 csi_sha_update(handle, NULL, output, padn);
662 /* get the hash result */
663 sha_get_data(handle, (uint32_t *)output);
666 /* convert the data endian according the sha mode */
667 if (sha_priv->mode == SHA_MODE_1) {
668 sha_reverse_order(p, 20);
669 } else if (sha_priv->mode == SHA_MODE_224) {
670 sha_reverse_order(p, 28);
671 } else if (sha_priv->mode == SHA_MODE_256) {
672 sha_reverse_order(p, 32);
673 } else if (sha_priv->mode == SHA_MODE_512) {
674 sha_reverse_order(p, 64);
675 } else if (sha_priv->mode == SHA_MODE_384) {
676 sha_reverse_order(p, 48);
679 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
681 sha_priv->last_left = 0;
692 \brief Get SHA status.
693 \param[in] handle sha handle to operate.
694 \return SHA status \ref sha_status_t
696 sha_status_t csi_sha_get_status(sha_handle_t handle)
698 ck_sha_priv_t *sha_priv = handle;
699 return sha_priv->status;