/* * (C) Copyright 2013-2016 * Allwinner Technology Co., Ltd. * * SPDX-License-Identifier: GPL-2.0+ */ #include "common.h" #include "asm/io.h" #include "asm/arch/ccmu.h" #include "asm/arch/ss.h" #include "asm/arch/mmu.h" #include "ss_op.h" #define ALG_SHA256 (0x13) #define ALG_RSA (0x20) #define ALG_MD5 (0x10) #define ALG_TRANG (0x1C) static u32 __aw_endian4(u32 data) { u32 d1, d2, d3, d4; d1= (data&0xff)<<24; d2= (data&0xff00)<<8; d3= (data&0xff0000)>>8; d4= (data&0xff000000)>>24; return (d1|d2|d3|d4); } static u32 __sha_padding(u32 data_size, u8* text, u32 hash_mode) { u32 i; u32 k, q; u32 size; u32 padding_buf[16]; u8 *ptext; k = data_size/64; q = data_size%64; ptext = (u8*)padding_buf; memset(padding_buf, 0, 16 * sizeof(u32)); if(q==0){ padding_buf[0] = 0x00000080; if(hash_mode) { padding_buf[14] = data_size>>29; padding_buf[15] = data_size<<3; padding_buf[14] = __aw_endian4(padding_buf[14]); padding_buf[15] = __aw_endian4(padding_buf[15]); } else { padding_buf[14] = data_size<<3; padding_buf[15] = data_size>>29; } for(i=0; i<64; i++){ text[k*64 + i] = ptext[i]; } size = (k + 1)*64; }else if(q<56) { for(i=0; i>29; padding_buf[15] = data_size<<3; padding_buf[14] = __aw_endian4(padding_buf[14]); padding_buf[15] = __aw_endian4(padding_buf[15]); } else { padding_buf[14] = data_size<<3; padding_buf[15] = data_size>>29; } for(i=0; i<64; i++){ text[k*64 + i] = ptext[i]; } size = (k + 1)*64; }else{ for(i=0; i>29; padding_buf[15] = data_size<<3; padding_buf[14] = __aw_endian4(padding_buf[14]); padding_buf[15] = __aw_endian4(padding_buf[15]); } else { padding_buf[14] = data_size<<3; padding_buf[15] = data_size>>29; } for(i=0; i<64; i++){ text[(k + 1)*64 + i] = ptext[i]; } size = (k + 2)*64; } return size; } static void __rsa_padding(u8 *dst_buf, u8 *src_buf, u32 data_len, u32 group_len) { int i = 0; memset(dst_buf, 0, group_len); for(i = group_len - data_len; i < group_len; i++) { dst_buf[i] = src_buf[group_len - 1 - i]; } } void sunxi_ss_open(void) { ss_open(); } void sunxi_ss_close(void) { ss_close(); } int sunxi_md5_calc(u8 *dst_addr, u32 dst_len, u8 *src_addr, u32 src_len) { u32 word_len = 0, src_align_len = 0; u32 total_bit_len = 0; task_queue task0 __aligned(CACHE_LINE_SIZE) = {0}; /* sha256 2word, sha512 4word*/ ALLOC_CACHE_ALIGN_BUFFER(u32, total_package_len, 4); ALLOC_CACHE_ALIGN_BUFFER(u8, p_sign, CACHE_LINE_SIZE); ss_open(); memset(p_sign, 0, sizeof(p_sign)); if (ss_get_ver() < 2) { /* CE1.0 */ src_align_len = __sha_padding(src_len, (u8 *)src_addr, 1); word_len = src_align_len>>2; task0.task_id = 0; task0.common_ctl = (ALG_MD5)|(1U << 31); task0.data_len = word_len; } else { /* CE2.0 */ src_align_len = ALIGN(src_len, 4); word_len = src_align_len>>2; total_bit_len = src_len<<3; total_package_len[0] = total_bit_len; total_package_len[1] = 0; task0.task_id = 0; task0.common_ctl = (ALG_MD5)|(1<<15)|(1U << 31); task0.key_descriptor = (u32)total_package_len; task0.data_len = total_bit_len; } task0.source[0].addr = (uint)src_addr; task0.source[0].length = word_len; task0.destination[0].addr = (uint)p_sign; task0.destination[0].length = dst_len>>2; task0.next_descriptor = 0; flush_cache((u32)&task0, sizeof(task0)); flush_cache((u32)p_sign, CACHE_LINE_SIZE); flush_cache((u32)src_addr, src_align_len); flush_cache((u32)total_package_len, sizeof(total_package_len)); ss_set_drq((u32)&task0); ss_irq_enable(task0.task_id); ss_ctrl_start(ALG_MD5); ss_wait_finish(task0.task_id); ss_pending_clear(task0.task_id); ss_ctrl_stop(); ss_irq_disable(task0.task_id); if (ss_check_err()) { printf("SS %s fail 0x%x\n", __func__, ss_check_err()); } invalidate_dcache_range((ulong)p_sign, (ulong)p_sign + CACHE_LINE_SIZE); /*copy data*/ memcpy(dst_addr, p_sign, dst_len); return 0; } int sunxi_sha_calc(u8 *dst_addr, u32 dst_len, u8 *src_addr, u32 src_len) { u32 word_len = 0,src_align_len = 0; u32 total_bit_len = 0; task_queue task0 __aligned(CACHE_LINE_SIZE) = {0}; /* sha256 2word, sha512 4word*/ ALLOC_CACHE_ALIGN_BUFFER(u32, total_package_len, 4); ALLOC_CACHE_ALIGN_BUFFER(u8, p_sign, CACHE_LINE_SIZE); memset(p_sign, 0, sizeof(p_sign)); if(ss_get_ver() < 2) { /* CE1.0 */ src_align_len = __sha_padding(src_len, (u8 *)src_addr, 1); word_len = src_align_len>>2; task0.task_id = 0; task0.common_ctl = (ALG_SHA256)|(1U << 31); task0.data_len = word_len; } else { /* CE2.0 */ src_align_len = ALIGN(src_len,4); word_len = src_align_len>>2; total_bit_len = src_len<<3; total_package_len[0] = total_bit_len; total_package_len[1] = 0; task0.task_id = 0; task0.common_ctl = (ALG_SHA256)|(1<<15)|(1U << 31); task0.key_descriptor = (u32)total_package_len; task0.data_len = total_bit_len; } task0.source[0].addr = (uint)src_addr; task0.source[0].length = word_len; task0.destination[0].addr = (uint)p_sign; task0.destination[0].length = 32>>2; task0.next_descriptor = 0; flush_cache((u32)&task0, sizeof(task0)); flush_cache((u32)p_sign, CACHE_LINE_SIZE); flush_cache((u32)src_addr, src_align_len); flush_cache((u32)total_package_len, sizeof(total_package_len)); ss_set_drq((u32)&task0); ss_irq_enable(task0.task_id); ss_ctrl_start(ALG_SHA256); ss_wait_finish(task0.task_id); ss_pending_clear(task0.task_id); ss_ctrl_stop(); ss_irq_disable(task0.task_id); if(ss_check_err()) { printf("SS %s fail 0x%x\n",__func__,ss_check_err()); } invalidate_dcache_range((ulong)p_sign,(ulong)p_sign+CACHE_LINE_SIZE); //copy data memcpy(dst_addr, p_sign, 32); return 0; } s32 sunxi_rsa_calc(u8 * n_addr, u32 n_len, u8 * e_addr, u32 e_len, u8 * dst_addr, u32 dst_len, u8 * src_addr, u32 src_len) { const u32 TEMP_BUFF_LEN = ((2048>>3) + CACHE_LINE_SIZE); u32 mod_bit_size = 2048; u32 mod_size_len_inbytes = mod_bit_size/8; u32 data_word_len = mod_size_len_inbytes/4; task_queue task0 __aligned(CACHE_LINE_SIZE) = {0}; ALLOC_CACHE_ALIGN_BUFFER(u8, p_n, TEMP_BUFF_LEN); ALLOC_CACHE_ALIGN_BUFFER(u8, p_e, TEMP_BUFF_LEN); ALLOC_CACHE_ALIGN_BUFFER(u8, p_src, TEMP_BUFF_LEN); ALLOC_CACHE_ALIGN_BUFFER(u8, p_dst, TEMP_BUFF_LEN); __rsa_padding(p_src, src_addr, src_len, mod_size_len_inbytes); __rsa_padding(p_n, n_addr, n_len, mod_size_len_inbytes); memset(p_e, 0, mod_size_len_inbytes); memcpy(p_e, e_addr, e_len); if(ss_get_ver() < 2) { /* CE1.0 */ task0.task_id = 0; task0.common_ctl = (ALG_RSA | (1U<<31)); task0.symmetric_ctl = 0; task0.asymmetric_ctl = (2<<28); /* rsa2048 */ task0.key_descriptor = (uint)p_e; task0.iv_descriptor = (uint)p_n; task0.ctr_descriptor = 0; task0.data_len = data_word_len; task0.source[0].addr= (uint)p_src; task0.source[0].length = data_word_len; task0.destination[0].addr= (uint)p_dst; task0.destination[0].length = data_word_len; task0.next_descriptor = 0; } else { /* CE2.0 */ task0.task_id = 0; task0.common_ctl = (ALG_RSA | (1U<<31)); task0.symmetric_ctl = 0; task0.asymmetric_ctl = (2048/32); /* rsa2048 */ task0.ctr_descriptor = 0; task0.source[0].addr= (uint)p_e; task0.source[0].length = data_word_len; task0.source[1].addr= (uint)p_n; task0.source[1].length = data_word_len; task0.source[2].addr= (uint)p_src; task0.source[2].length = data_word_len; task0.data_len += task0.source[0].length; task0.data_len += task0.source[1].length; task0.data_len += task0.source[2].length; task0.data_len *= 4; /* byte len */ task0.destination[0].addr= (uint)p_dst; task0.destination[0].length = data_word_len; } flush_cache((u32)&task0, sizeof(task0)); flush_cache((u32)p_n, mod_size_len_inbytes); flush_cache((u32)p_e, mod_size_len_inbytes); flush_cache((u32)p_src, mod_size_len_inbytes); flush_cache((u32)p_dst, mod_size_len_inbytes); ss_set_drq((u32)&task0); ss_irq_enable(task0.task_id); ss_ctrl_start(ALG_RSA); ss_wait_finish(task0.task_id); ss_pending_clear(task0.task_id); ss_ctrl_stop(); ss_irq_disable(task0.task_id); if(ss_check_err()) { printf("SS %s fail 0x%x\n",__func__,ss_check_err()); } invalidate_dcache_range((ulong)p_dst,(ulong)p_dst+mod_size_len_inbytes); __rsa_padding(dst_addr, p_dst, mod_bit_size/64, mod_bit_size/64); return 0; } int sunxi_create_rssk(u8 *rssk_buf, u32 rssk_byte) { u32 total_bit_len = 0; task_queue task0 __aligned(CACHE_LINE_SIZE) = {0}; ALLOC_CACHE_ALIGN_BUFFER(u32, total_package_len, 4); ALLOC_CACHE_ALIGN_BUFFER(u8, p_sign, CACHE_LINE_SIZE); memset(p_sign, 0, sizeof(p_sign)); sunxi_ss_open(); if (rssk_buf == NULL) { return -1; } total_bit_len = rssk_byte << 3; total_package_len[0] = total_bit_len; total_package_len[1] = 0; task0.task_id = 0; task0.common_ctl = (ALG_TRANG)|(0x1U<<31); task0.key_descriptor = (uint)total_package_len; task0.data_len = total_bit_len; task0.source[0].addr = 0; task0.source[0].length = 0; task0.destination[0].addr = (uint)p_sign; task0.destination[0].length = (rssk_byte>>2); task0.next_descriptor = 0; flush_cache((u32)&task0, sizeof(task0)); flush_cache((u32)p_sign, CACHE_LINE_SIZE); flush_cache((u32)total_package_len, sizeof(total_package_len)); ss_set_drq((u32)&task0); ss_irq_enable(task0.task_id); ss_ctrl_start(ALG_TRANG); ss_wait_finish(task0.task_id); ss_pending_clear(task0.task_id); ss_ctrl_stop(); ss_irq_disable(task0.task_id); if (ss_check_err()) { printf("RSSK %s fail 0x%x\n", __func__, ss_check_err()); } invalidate_dcache_range((ulong)p_sign, (ulong)p_sign+CACHE_LINE_SIZE); /*copy data*/ memcpy(rssk_buf, p_sign, rssk_byte); return 0; } #ifdef SUNXI_HASH_TEST int do_sha256_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u8 hash[32] = {0}; u32 x1 = simple_strtol(argv[1], NULL, 16); u32 x2 = simple_strtol(argv[2], NULL, 16); if(argc < 3) { return -1; } printf("src = 0x%x, len = 0x%x\n", x1,x2); tick_printf("sha256 test start 0\n"); sunxi_ss_open(); sunxi_sha_calc(hash, 32, (u8*)x1,x2); tick_printf("sha256 test end\n"); sunxi_dump(hash,32); return 0; } U_BOOT_CMD( sha256_test, 3, 0, do_sha256_test, "do a sha256 test, arg1: src address, arg2: len(hex)", "NULL" ); #endif