1 /*
2 * Copyright (C) 2017-2024 Alibaba Group Holding Limited
3 */
4
5 /*******************************************************
6 * @file wj_sha.c
7 * @brief source file for sha csi driver
8 * @version V2.0
9 * @date 14. Sept 2020
10 * ******************************************************/
11
12 #include <drv/sha.h>
13 #include <drv/irq.h>
14
15 /**
16 * Different modes get different plaintext blocks
17 */
18 #define SHA_GET_BOLOCK_SIZE_BYTES(_mod_) (((_mod_) < SHA_MODE_512) ? (uint32_t)64 : (uint32_t)128)
19
20 /**
21 * Different modes get different data lengths
22 * \note SHA-1\SHA-224\SHA-256 need 2 * 4 = 8 bytes
23 * SHA-512\SHA-384 need 4 * 4 = 16 bytes
24 */
25 #define SHA_GET_MSGLEN_TAIL_4BYTES(_mod_) (((_mod_) < SHA_MODE_512) ? (uint32_t)2 : (uint32_t)4)
26
27 /**
28 * Number of result message digest bytes retrieved by sha mode
29 */
30 #define SHA_GET_MSGDIGEST_BYTES(_mod_) (((_mod_) == SHA_MODE_1 ) ? (uint32_t)20 : \
31 ((_mod_) == SHA_MODE_256) ? (uint32_t)32 : \
32 ((_mod_) == SHA_MODE_224) ? (uint32_t)28 : \
33 ((_mod_) == SHA_MODE_512) ? (uint32_t)64 : \
34 ((_mod_) == SHA_MODE_384) ? (uint32_t)48 : \
35 (uint32_t)20)
36
37 #define SHA_ALG_ALIGN_SORT(_idx_) (_idx_ % 2U ? ((_idx_ - 1U) >> 1) : ((_idx_ >> 1) + 8U))
38
39 #define SHA_ALG_SWAP(_x_, _y_) { \
40 uint8_t z = (uint8_t)*_x_; \
41 *_x_ = (uint8_t)*_y_; \
42 *_y_ = z; \
43 }
44
45 #define SHA_ALG_ALIGN_4BYTE(_len_) (((_len_) % 4U) ? ((((_len_) >> 2U) << 2U) + 4U) : (_len_))
46
47
48 #define SHA_ALG_SELECT_MIN(_x_, _y_) (((_x_) < (_y_)) ? (_x_) : (_y_))
49
50 #define SHA_WAIT_WRITED_10S (10000U)
51
52 #define SHA_WAIT_IS_TIMEOUT(_time_ms_, _result_) { \
53 do { \
54 if (_time_ms_ >= SHA_WAIT_WRITED_10S) { \
55 _result_ = -1; \
56 } \
57 } while(0); \
58 }
59
60 /*<! Private function documentation */
61
62 /**
63 \brief SHA data sort
64 \param[in] d_addr operate data dest
65 \param[in] s_addr operate data source
66 \param[in] idx current data idx
67 \return null
68 */
wj_sha_alg_sort(uint8_t * d_addr,uint8_t * s_addr,uint8_t idx)69 void wj_sha_alg_sort(uint8_t *d_addr, uint8_t *s_addr, uint8_t idx)
70 {
71 *(d_addr + (idx << 2) + 0U) = *(s_addr + 0U);
72 *(d_addr + (idx << 2) + 1U) = *(s_addr + 1U);
73 *(d_addr + (idx << 2) + 2U) = *(s_addr + 2U);
74 *(d_addr + (idx << 2) + 3U) = *(s_addr + 3U);
75 }
76
77 /**
78 \brief SHA data flipping
79 \param[in] p operate start address
80 \param[in] n operate data length
81 \return null
82 */
wj_sha_alg_reverse(uint8_t * p,uint8_t n)83 void wj_sha_alg_reverse(uint8_t *p, uint8_t n)
84 {
85 if (n) {
86 SHA_ALG_SWAP((p + 0U), (p + 3U)); ///< BYTE0 <<---SWAP--->> BYTE3
87 SHA_ALG_SWAP((p + 1U), (p + 2U)); ///< BYTE1 <<---SWAP--->> BYTE2
88
89 wj_sha_alg_reverse((p + 4U), (n - 1U)); ///< offset next address(uint32_t) and reduce operate data count
90 }
91 }
92
93 /**
94 \brief SHA interrupt handling function
95 \param[in] arg Callback function member variables
96 \return null
97 */
wj_sha_irq_handler(void * arg)98 void wj_sha_irq_handler(void *arg)
99 {
100 csi_sha_t *sha = (csi_sha_t *)arg;
101 uint32_t sha_irq_state = 0U;
102 ///< TODO:获取中断状态到sha_irq_state
103 if (sha_irq_state) {
104 if (sha->callback) {
105 sha->callback(sha, SHA_EVENT_COMPLETE, sha->arg);
106 }
107
108 ///< TODO:清除SHA 中断状态
109 }
110 }
111
112 /**
113 \brief update the engine
114 \param[in] sha sha handle to operate.
115 \param[in] context Pointer to the sha context
116 \param[in] input Pointer to the Source data
117 \param[in] size the data size
118 \return \ref csi_error_t
119 */
wj_sha_update_sub(csi_sha_t * sha,csi_sha_context_t * context,const void * input,uint32_t size)120 csi_error_t wj_sha_update_sub(csi_sha_t *sha, csi_sha_context_t *context, const void *input, uint32_t size)
121 {
122 CSI_PARAM_CHK(sha, CSI_ERROR);
123 CSI_PARAM_CHK(context, CSI_ERROR);
124 csi_error_t ret = CSI_OK;
125
126 uint8_t *p_data_in = (uint8_t *)input;
127
128 sha->state.busy = 1U;
129
130 *(p_data_in + size) = 0x80U;
131
132 ///< TODO:写入计算值
133
134 ///< TODO:开始SHA计算
135
136 mdelay(1U); ///<! Must be kept, otherwise the data is prone to error
137
138 sha->state.busy = 0U;
139
140 return ret;
141 }
142
143 /*<! Public function documentation */
144
145 /**
146 \brief Initialize SHA Interface. 1. Initializes the resources needed for the SHA interface 2.registers event callback function
147 \param[in] sha operate handle.
148 \param[in] idx index of sha
149 \return \ref csi_error_t
150 */
csi_sha_init(csi_sha_t * sha,uint32_t idx)151 csi_error_t csi_sha_init(csi_sha_t *sha, uint32_t idx)
152 {
153 CSI_PARAM_CHK(sha, CSI_ERROR);
154 csi_error_t ret = CSI_OK;
155
156 ///< 获取中断号、基地址等相关信息
157 if (0 == target_get(DEV_WJ_SHA_TAG, idx, &sha->dev)) {
158
159 ///< TODO:清除SHA所有的寄存器
160
161 sha->state.busy = 0U;
162 } else {
163 ret = CSI_ERROR;
164 }
165
166 return ret;
167 }
168
169 /**
170 \brief De-initialize SHA Interface. stops operation and releases the software resources used by the interface
171 \param[in] sha sha handle to operate.
172 \return none
173 */
csi_sha_uninit(csi_sha_t * sha)174 void csi_sha_uninit(csi_sha_t *sha)
175 {
176 CSI_PARAM_CHK_NORETVAL(sha);
177
178 ///< TODO:清除SHA所有的寄存器
179 }
180
181 /**
182 \brief attach the callback handler to SHA
183 \param[in] sha operate handle.
184 \param[in] callback callback function
185 \param[in] arg callback's param
186 \return error code
187 */
csi_sha_attach_callback(csi_sha_t * sha,void * callback,void * arg)188 csi_error_t csi_sha_attach_callback(csi_sha_t *sha, void *callback, void *arg)
189 {
190 CSI_PARAM_CHK(sha, CSI_ERROR);
191
192 sha->callback = callback;
193 sha->arg = arg;
194 ///< 附着中断处理函数
195 csi_irq_attach((uint32_t)sha->dev.irq_num, &wj_sha_irq_handler, &sha->dev);
196 ///< 使能SHA中断
197 csi_irq_enable((uint32_t)sha->dev.irq_num);
198
199 return CSI_OK;
200 }
201
202 /**
203 \brief detach the callback handler
204 \param[in] sha operate handle.
205 */
csi_sha_detach_callback(csi_sha_t * sha)206 void csi_sha_detach_callback(csi_sha_t *sha)
207 {
208 CSI_PARAM_CHK_NORETVAL(sha);
209 sha->callback = NULL;
210 sha->arg = NULL;
211 ///< 关闭SHA 中断功能
212 csi_irq_disable((uint32_t)sha->dev.irq_num);
213 ///< 清除SHA中断附着
214 csi_irq_detach((uint32_t)sha->dev.irq_num);
215 }
216
217 /**
218 \brief config sha mode.
219 \param[in] sha sha handle to operate.
220 \param[in] context Pointer to the sha context
221 \param[in] mode sha mode \ref csi_sha_mode_t
222 \return \ref csi_error_t
223 */
csi_sha_start(csi_sha_t * sha,csi_sha_context_t * context,csi_sha_mode_t mode)224 csi_error_t csi_sha_start(csi_sha_t *sha, csi_sha_context_t *context, csi_sha_mode_t mode)
225 {
226 CSI_PARAM_CHK(sha, CSI_ERROR);
227 CSI_PARAM_CHK(context, CSI_ERROR);
228 csi_error_t ret = CSI_OK;
229
230 switch (mode) {
231 case SHA_MODE_1:
232 case SHA_MODE_256:
233 case SHA_MODE_224:
234 case SHA_MODE_512:
235 case SHA_MODE_384:
236 ///< TODO:设置SHA 模式
237 ///< TODO:清除 SHA HASH 值
238 ///< TODO:清除 SHA DATA 值
239
240 memset((void *)&context->mode, 0, sizeof(csi_sha_context_t));
241 context->mode = mode;
242 ///< TODO:SHA 使能中断
243 ///< TODO:SHA 使能初始值
244
245 ///< TODO:把SHA存储密文的寄存器中的内容复制sizeof(context->state)大小到context->state
246 break;
247
248 case SHA_MODE_512_256:
249 case SHA_MODE_512_224:
250 ret = CSI_UNSUPPORTED;
251 break;
252
253 default:
254 ret = CSI_ERROR;
255 break;
256 }
257
258 return ret;
259 }
260
261 /**
262 \brief update the engine
263 \param[in] sha sha handle to operate.
264 \param[in] context Pointer to the sha context
265 \param[in] input Pointer to the Source data
266 \param[in] size the data size
267 \return \ref csi_error_t
268 */
csi_sha_update(csi_sha_t * sha,csi_sha_context_t * context,const void * input,uint32_t size)269 csi_error_t csi_sha_update(csi_sha_t *sha, csi_sha_context_t *context, const void *input, uint32_t size)
270 {
271 CSI_PARAM_CHK(sha, CSI_ERROR);
272 CSI_PARAM_CHK(context, CSI_ERROR);
273 csi_error_t ret = CSI_OK;
274
275 uint8_t *p_data_in = (uint8_t *)input;
276 uint32_t block_size;
277 uint32_t timecount = 0U;
278 uint32_t left;
279 uint32_t length;
280
281 sha->state.busy = 1U;
282
283 ///< TODO:设置SHA 模式
284 ///< TODO:用context->state初始化HASH
285
286 block_size = SHA_GET_BOLOCK_SIZE_BYTES(context->mode);
287
288 context->total[0] += size;
289 left = strlen((const char *)context->buffer); ///< Get unused message
290
291 /**
292 * If there is any unused message, it will be added to the new message for calculation
293 */
294 if (left) {
295 memcpy((uint8_t *)context->buffer + left, p_data_in, SHA_ALG_SELECT_MIN(block_size - left, size)); ///< pad input message to complete block
296 size += left; ///< input message size need add original message size(only unused)
297 } else {
298 memcpy((uint8_t *)context->buffer, p_data_in, SHA_ALG_SELECT_MIN(block_size, size));
299 }
300
301 length = size; ///< message size
302
303 if (length >= block_size) { ///< if length > block size, need accumulate two times least
304
305 do {
306 ///< TODO:写入待计算值 context->buffer
307
308 ///< TODO:开始SHA 计算
309
310 mdelay(1U); ///<! Must be kept, otherwise the data is prone to error
311
312 length -= block_size;
313 p_data_in += (block_size - left); ///< input address offset
314 left = 0U;
315
316 memcpy((uint8_t *)context->buffer, p_data_in, block_size);
317
318 SHA_WAIT_IS_TIMEOUT(++timecount, ret);
319
320 if (ret != CSI_OK) {
321 break;
322 }
323 } while (length >= block_size);
324
325 memset((uint8_t *)context->buffer, 0, block_size);
326
327 memcpy((uint8_t *)context->buffer, p_data_in, (size & (block_size - 1U)));
328
329 }
330
331 ///< TODO:获取HASH用context->state
332
333 sha->state.busy = 0U;
334
335 return ret;
336 }
337
338 /**
339 \brief accumulate the engine (async mode)
340 \param[in] sha sha handle to operate.
341 \param[in] context Pointer to the sha context
342 \param[in] input Pointer to the Source data
343 \param[in] size the data size
344 \return \ref csi_error_t
345 */
csi_sha_update_async(csi_sha_t * sha,csi_sha_context_t * context,const void * input,uint32_t size)346 csi_error_t csi_sha_update_async(csi_sha_t *sha, csi_sha_context_t *context, const void *input, uint32_t size)
347 {
348 CSI_PARAM_CHK(sha, CSI_ERROR);
349 CSI_PARAM_CHK(context, CSI_ERROR);
350
351 csi_error_t ret = CSI_UNSUPPORTED;
352
353 return ret;
354 }
355
356 /**
357 \brief finish the engine
358 \param[in] sha sha handle to operate.
359 \param[in] context Pointer to the sha context
360 \param[out] output Pointer to the result data
361 \param[out] out_size Pointer to the result data size(bytes)
362 \return \ref csi_error_t
363 */
csi_sha_finish(csi_sha_t * sha,csi_sha_context_t * context,void * output,uint32_t * out_size)364 csi_error_t csi_sha_finish(csi_sha_t *sha, csi_sha_context_t *context, void *output, uint32_t *out_size)
365 {
366 CSI_PARAM_CHK(sha, CSI_ERROR);
367 CSI_PARAM_CHK(context, CSI_ERROR);
368 csi_error_t ret = CSI_OK;
369
370 uint32_t *p_data_in = (uint32_t *)context->buffer;
371 uint8_t *out_buf = (uint8_t *)output;
372 uint32_t i;
373 uint32_t msg_length;
374 uint32_t block_size;
375 uint32_t length;
376 uint32_t size = context->total[0];
377 uint32_t pad_buf[4] = {0U};
378 uint64_t pad_bit_len;
379
380 ///< TODO:设置SHA 模式
381 ///< TODO:用context->state初始化HASH
382
383 block_size = SHA_GET_BOLOCK_SIZE_BYTES(context->mode);
384 msg_length = SHA_GET_MSGLEN_TAIL_4BYTES(context->mode);
385
386 pad_bit_len = (uint64_t)size << 3U; ///< write message length into memory behind message
387
388 length = (strlen((char *)context->buffer) + (msg_length << 2U)) + 1U; ///< message size + extra length + format(0x80)
389
390 if (length > block_size) {
391 wj_sha_update_sub(sha, context, p_data_in, size);
392 memset((uint8_t *)context->buffer, 0, sizeof(context->buffer));
393 } else {
394 pad_buf[0] = 0x80U;
395 memcpy((uint8_t *)p_data_in + (size % block_size), &pad_buf[0], sizeof(uint32_t)); ///< add tail(msg bit length)
396 }
397
398 pad_buf[1] = (uint32_t)pad_bit_len >> 16;
399 pad_buf[2] = (uint32_t)pad_bit_len;
400 wj_sha_alg_reverse((uint8_t *)&pad_buf[1], 2U);
401
402 memcpy((uint8_t *)p_data_in + block_size - 8U, &pad_buf[1], sizeof(uint32_t) << 1); ///< add tail(msg bit length)
403
404 ///< TODO:写入待计算值 p_data_in
405
406 ///< TODO:开始SHA计算
407
408 mdelay(1U); ///<! Must be kept, otherwise the data is prone to error
409
410 *out_size = SHA_GET_MSGDIGEST_BYTES(context->mode);
411
412 if (*out_size < SHA_GET_MSGDIGEST_BYTES(SHA_MODE_384)) {
413 ///< TODO:把SHA存储密文的寄存器中的内容复制out_size大小到context->buffer
414 wj_sha_alg_reverse(context->buffer, ((uint8_t)*out_size) >> 2U); ///< Flip the last result data
415 memcpy(out_buf, context->buffer, *out_size);
416 } else {
417 ///< TODO:把SHA存储密文的寄存器中的内容复制64大小到context->buffer
418 wj_sha_alg_reverse(context->buffer, 16U); ///< Flip the last result data
419
420 for (i = 0U; i < (*out_size >> 2); i++) {
421 wj_sha_alg_sort(out_buf, context->buffer + (SHA_ALG_ALIGN_SORT(i) << 2), i);
422 }
423 }
424
425 ///< TODO:开始SHA HASH
426 ///< TODO:开始SHA DATA
427
428 /**
429 * clean cache
430 */
431 memset((uint8_t *)context->total, 0, sizeof(context->total));
432 memset((uint8_t *)context->state, 0, sizeof(context->state));
433 memset((uint8_t *)context->buffer, 0, sizeof(context->buffer));
434
435 return ret;
436 }
437
438 /**
439 \brief Get SHA state.
440 \param[in] sha sha handle to operate.
441 \param[out] state sha state \ref csi_sha_state_t.
442 \return \ref csi_error_t
443 */
csi_sha_get_state(csi_sha_t * sha,csi_sha_state_t * state)444 csi_error_t csi_sha_get_state(csi_sha_t *sha, csi_sha_state_t *state)
445 {
446 CSI_PARAM_CHK(sha, CSI_ERROR);
447 CSI_PARAM_CHK(state, CSI_ERROR);
448
449 state->busy = sha->state.busy;
450 state->error = sha->state.error;
451
452 return CSI_OK;
453 }
454
455 #ifdef CONFIG_PM
wj_sha_pm_action(csi_dev_t * dev,csi_pm_dev_action_t action)456 csi_error_t wj_sha_pm_action(csi_dev_t *dev, csi_pm_dev_action_t action)
457 {
458 CSI_PARAM_CHK(dev, CSI_ERROR);
459
460 csi_error_t ret = CSI_OK;
461 csi_pm_dev_t *pm_dev = &dev->pm_dev;
462
463 switch (action) {
464 case PM_DEV_SUSPEND:
465 ///< TODO:恢复SHA 寄存器
466 break;
467
468 case PM_DEV_RESUME:
469 ///< TODO:保存SHA 寄存器
470 break;
471
472 default:
473 ret = CSI_ERROR;
474 break;
475 }
476
477 return ret;
478 }
479
csi_sha_enable_pm(csi_sha_t * sha)480 csi_error_t csi_sha_enable_pm(csi_sha_t *sha)
481 {
482 ///< TODO:注册 SHA 低功耗处理函数
483 return csi_pm_dev_register(&sha->dev, wj_sha_pm_action, 25U, 0U);
484 }
485
csi_sha_disable_pm(csi_sha_t * sha)486 void csi_sha_disable_pm(csi_sha_t *sha)
487 {
488 csi_pm_dev_unregister(&sha->dev);
489 }
490 #endif
491