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_v1.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 uint32_t sha_buffer[32];
49 #ifndef CONFIG_SHA_SUPPORT_MUL_THREAD
50 static ck_sha_priv_t sha_handle[CONFIG_SHA_NUM];
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 */
67 #define ERR_SHA(errno) (CSI_DRV_ERRNO_SHA_BASE | errno)
68 #define SHA_NULL_PARAM_CHK(para) \
71 return ERR_SHA(EDRV_PARAMETER); \
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);
81 ck_sha_reg_t *sha_reg = NULL;
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;
88 static uint8_t sha_result[64] = {0x0};
90 static int32_t sha_set_mode(sha_mode_e mode)
92 sha_reg->SHA_MODE &= ~0x7;
93 sha_reg->SHA_MODE |= mode;
97 static void sha_set_source_message(uint32_t baseaddr)
99 sha_reg->SHA_BASEADDR = baseaddr;
102 static void sha_set_dest_message(uint32_t destaddr)
104 sha_reg->SHA_DESTADDR = destaddr;
107 static void sha_enable_without_count(void)
109 sha_reg->SHA_MODE |= 1<<25;
112 static void sha_disable_without_count(void)
114 sha_reg->SHA_MODE &= ~(1<<25);
117 static void sha_set_message_count(uint32_t count)
119 sha_reg->SHA_COUNTER0 = count;
120 sha_reg->SHA_COUNTER1 = 0;
123 static int32_t sha_enable_initial(void)
125 sha_reg->SHA_MODE |= 1 << SHA_INIT_OFFSET;
129 static int32_t sha_disable_initial(void)
131 sha_reg->SHA_MODE &= ~(1 << SHA_INIT_OFFSET);
135 static int32_t sha_enable_calculate(void)
137 sha_reg->SHA_CON |= 1;
141 static int32_t sha_message_done(void)
143 while(sha_reg->SHA_CON & 0x1);
147 static void sha_new_encode(void)
149 sha_reg->SHA_INTSTATE = 0;
150 sha_reg->SHA_MODE = 0;
153 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
154 static int32_t sha_restore_context(sha_handle_t handle, uint32_t *data)
156 uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
159 for (i = 0; i < 16; i++) {
165 static int32_t sha_save_context(sha_handle_t handle, uint32_t *data)
167 uint32_t *result = (uint32_t *)&sha_reg->SHA_H0L;
170 for (i = 0; i < 16; i++) {
177 static inline void sha_reverse_order(uint8_t *pdata, int32_t length)
179 uint8_t input_data[length];
180 uint8_t result[length];
183 memcpy((void *)input_data, (void *)pdata, length);
185 for (i = 0; i < length; i++) {
188 result[i] = input_data[tmp + 3 - i];
191 memcpy((void *)pdata, (void *)result, length);
195 \brief get sha handle count.
196 \return sha handle count
198 int32_t csi_sha_get_instance_count(void)
200 return target_get_sha_count();
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
209 sha_handle_t csi_sha_initialize(sha_handle_t handle, sha_event_cb_t cb_event)
211 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
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));
219 sha_priv->first_cal = 1;
222 if (idx < 0 || idx >= CONFIG_SHA_NUM) {
228 /* obtain the sha information */
229 int32_t real_idx = target_get_sha(idx, &base, &irq);
231 if (real_idx != idx) {
234 ck_sha_priv_t *sha_priv = &sha_handle[idx];
236 sha_priv->base = base;
239 /* initialize the sha context */
240 sha_priv->cb = cb_event;
241 sha_priv->status.busy = 0;
243 return (sha_handle_t)sha_priv;
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.
251 int32_t csi_sha_uninitialize(sha_handle_t handle)
253 SHA_NULL_PARAM_CHK(handle);
255 ck_sha_priv_t *sha_priv = handle;
262 \brief Get driver capabilities.
263 \param[in] handle sha handle to operate.
264 \return \ref sha_capabilities_t
266 sha_capabilities_t csi_sha_get_capabilities(sha_handle_t handle)
268 return driver_capabilities;
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
278 int32_t csi_sha_config(sha_handle_t handle, sha_mode_e mode, sha_endian_mode_e endian_mode)
280 SHA_NULL_PARAM_CHK(handle);
282 ck_sha_priv_t *sha_priv = handle;
283 sha_reg = (ck_sha_reg_t *)(sha_priv->base);
285 /* config the sha mode */
287 case SHA_MODE_512_256:
288 case SHA_MODE_512_224:
289 return ERR_SHA(EDRV_UNSUPPORTED);
296 sha_priv->mode = mode;
300 return ERR_SHA(EDRV_PARAMETER);
307 \brief start the engine
308 \param[in] handle sha handle to operate.
309 \param[in] context Pointer to the sha context.
312 int32_t csi_sha_starts(sha_handle_t handle, void *context)
314 SHA_NULL_PARAM_CHK(handle);
316 ck_sha_priv_t *sha_priv = handle;
317 sha_priv->status.busy = 1;
320 sha_set_mode(sha_priv->mode);
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;
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
340 int32_t csi_sha_update(sha_handle_t handle, void *context, const void *input, uint32_t len)
342 SHA_NULL_PARAM_CHK(handle);
343 SHA_NULL_PARAM_CHK(input);
345 return ERR_SHA(EDRV_PARAMETER);
348 ck_sha_priv_t *sha_priv = handle;
349 sha_reg = (ck_sha_reg_t *)(sha_priv->base);
351 uint8_t total_len_num;
353 if (sha_priv->mode < 4) {
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;
373 sha_priv->total += len;
374 sha_priv->total &= 0xffffffff;
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;
385 total[0] &= 0xffffffff;
387 uint8_t *p = (uint8_t *)input;
388 /* when the text is not aligned by block and len > fill */
389 if (left && len >= fill) {
391 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
392 memset(((uint8_t *)sha_buffer + left), 0x0, sizeof(sha_priv->sha_buffer) - left);
394 memset(((uint8_t *)sha_buffer + left), 0x0, sizeof(sha_buffer) - left);
396 sha_buffer[index + total_len_num - 1] = total_length;
398 sha_disable_without_count();
399 sha_set_message_count(left << 3);
401 memcpy((void *)(((uint8_t *)sha_buffer) + left), p, fill);
404 sha_enable_without_count();
405 sha_set_message_count(block_size << 3);
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();
413 sha_disable_initial();
416 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
417 sha_restore_context(handle, (uint32_t *)sha_priv->state);
420 sha_enable_calculate();
423 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
424 sha_save_context(handle, (uint32_t *)sha_priv->state);
428 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
429 sha_priv->first_cal = 0;
436 /* calculate the hash by block */
437 while (len >= block_size) {
439 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
440 memset(sha_buffer, 0, sizeof(sha_priv->sha_buffer));
442 memset(sha_buffer, 0, sizeof(sha_buffer));
444 sha_buffer[total_len_num - 1] = total_length;
446 sha_set_source_message((uint32_t)sha_buffer);
447 sha_disable_without_count();
448 sha_set_message_count(0);
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);
456 sha_set_dest_message((uint32_t)sha_result);
457 if (first_cal == 0) {
458 sha_enable_initial();
460 sha_disable_initial();
462 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
463 sha_restore_context(handle, (uint32_t *)sha_priv->state);
466 sha_enable_calculate();
468 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
469 sha_save_context(handle, (uint32_t *)sha_priv->state);
471 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
472 sha_priv->first_cal = 0;
480 /* when the text is not aligned by block and len < fill */
482 memcpy((void *)(((uint8_t *)sha_buffer) + left), p, len);
485 sha_priv->status.busy = 0;
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
497 int32_t csi_sha_finish(sha_handle_t handle, void *context, void *output)
499 SHA_NULL_PARAM_CHK(handle);
500 SHA_NULL_PARAM_CHK(output);
502 ck_sha_priv_t *sha_priv = handle;
504 if (sha_priv->mode < 4) {
510 #ifdef CONFIG_SHA_SUPPORT_MUL_THREAD
511 uint32_t last = sha_priv->total & (block_size - 1);
513 uint32_t last = total[0] & (block_size - 1);
515 uint32_t padn = block_size - last;
519 csi_sha_update(handle, NULL, output, padn);
521 uint8_t result_len = 20;
522 /* convert the data endian according the sha mode */
523 if (sha_priv->mode == SHA_MODE_1) {
525 } else if (sha_priv->mode == SHA_MODE_224) {
527 } else if (sha_priv->mode == SHA_MODE_256) {
529 } else if (sha_priv->mode == SHA_MODE_512) {
531 } else if (sha_priv->mode == SHA_MODE_384) {
534 sha_reverse_order(sha_result, result_len);
535 memcpy((uint8_t*)output, sha_result, result_len);
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;
543 memset(sha_buffer, 0, sizeof(sha_buffer));
551 \brief Get SHA status.
552 \param[in] handle sha handle to operate.
553 \return SHA status \ref sha_status_t
555 sha_status_t csi_sha_get_status(sha_handle_t handle)
557 ck_sha_priv_t *sha_priv = handle;
558 return sha_priv->status;