• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include "drv_osal_lib.h"
20 #include "hal_efuse.h"
21 #include "hal_otp.h"
22 #include "drv_cipher_kapi.h"
23 #include "drv_klad.h"
24 #include "securec.h"
25 
26 #define KLAD_REG_BASE_ADDR                      g_cipher_klad_base
27 #define KLAD_BASE_BUF_SIZE                      0x100
28 #define KLAD_REG_KLAD_CTRL                      (KLAD_REG_BASE_ADDR + 0x00)
29 #define KLAD_REG_DAT_IN                         (KLAD_REG_BASE_ADDR + 0x10)
30 #define KLAD_REG_ENC_OUT                        (KLAD_REG_BASE_ADDR + 0x20)
31 
32 #define CIPHER_WAIT_IDLE_TIMES          1000
33 
34 static hi_u8 *g_cipher_klad_base = HI_NULL;
35 
hal_cipher_klad_config(hi_u32 chn_id,hi_u32 opt_id,hi_cipher_klad_target target,hi_bool is_decrypt)36 hi_s32 hal_cipher_klad_config(hi_u32 chn_id, hi_u32 opt_id, hi_cipher_klad_target target, hi_bool is_decrypt)
37 {
38     hi_s32 ret;
39     klad_ctrl ctrl;
40 
41     /* Load efuse or OTP key to KLAD */
42     ret = hal_efuse_otp_load_cipher_key(chn_id, opt_id);
43     if (ret != HI_SUCCESS) {
44         hi_log_print_func_err(hal_efuse_otp_load_cipher_key, ret);
45         return ret;
46     }
47 
48     ctrl.u32 = 0;
49     ctrl.bits.klad2ci_addr = chn_id;
50     ctrl.bits.type = target;
51     ctrl.bits.decrypt = is_decrypt;
52     ctrl.bits.start = KLAD_CTRL_NOT_START;
53 
54     (hi_void)hal_cipher_write_reg(KLAD_REG_KLAD_CTRL, ctrl.u32);
55     return HI_SUCCESS;
56 }
57 
hal_cipher_start_klad(hi_u32 block_num)58 hi_void hal_cipher_start_klad(hi_u32 block_num)
59 {
60     klad_ctrl ctrl;
61 
62     ctrl.u32 = 0;
63     hal_cipher_read_reg(KLAD_REG_KLAD_CTRL, &ctrl.u32);
64 
65     /* High 128bits is just meaningful for loading cipher 256 bits key, and meaningless to rsa. */
66     if (block_num == KLAD_HIGH_128BIT_BLOCK) {
67         ctrl.bits.high_low_128bit_flag = KLAD_CTRL_HIGH_128BIT_FLAG;
68     } else {
69         ctrl.bits.high_low_128bit_flag = KLAD_CTRL_LOW_128BIT_FLAG;
70     }
71 
72     /* start */
73     ctrl.bits.start = KLAD_CTRL_START;
74     hal_cipher_write_reg(KLAD_REG_KLAD_CTRL, ctrl.u32);
75 }
76 
hal_cipher_set_klad_data(const hi_u32 * data_in,hi_u32 data_len_in_word)77 hi_void hal_cipher_set_klad_data(const hi_u32 *data_in, hi_u32 data_len_in_word)
78 {
79     hi_u32 i;
80 
81     /* The length of klad input key is 16 bytes. */
82     for (i = 0; i < data_len_in_word; i++) {
83         (hi_void)hal_cipher_write_reg(KLAD_REG_DAT_IN + i * WORD_WIDTH, data_in[i]);
84     }
85 }
86 
hal_cipher_get_klad_data(hi_u32 * data_out,hi_u32 data_len_in_word)87 hi_void hal_cipher_get_klad_data(hi_u32 *data_out, hi_u32 data_len_in_word)
88 {
89     hi_u32 i;
90 
91     /* The length of klad output key is 16 bytes. */
92     for (i = 0; i < data_len_in_word; i++) {
93         (hi_void)hal_cipher_read_reg(KLAD_REG_ENC_OUT + i * WORD_WIDTH, &data_out[i]);
94     }
95 }
96 
hal_cipher_wait_klad_done(hi_void)97 hi_s32 hal_cipher_wait_klad_done(hi_void)
98 {
99     hi_s32 i;
100     klad_ctrl ctrl;
101 
102     for (i = 0; i < CIPHER_WAIT_IDLE_TIMES; i++) {
103         ctrl.u32 = 0;
104         hal_cipher_read_reg(KLAD_REG_KLAD_CTRL, &ctrl.u32);
105         if (ctrl.bits.start == KLAD_CTRL_NOT_START) {
106             return HI_SUCCESS;
107         }
108     }
109 
110     if (i >= CIPHER_WAIT_IDLE_TIMES) {
111         hi_log_error("Klad wait time out!\n");
112         return HI_ERR_CIPHER_TIMEOUT;
113     }
114 
115     return HI_SUCCESS;
116 }
117 
hal_cipher_klad_init(hi_void)118 static hi_void hal_cipher_klad_init(hi_void)
119 {
120     hi_u32 crg_value = 0;
121     hi_u32 *sys_addr = HI_NULL;
122 
123     sys_addr = crypto_ioremap_nocache(KLAD_CRG_ADDR_PHY, KLAD_BASE_BUF_SIZE);
124     if (sys_addr == HI_NULL) {
125         hi_log_error("ERROR: sys_addr ioremap with nocache failed!!\n");
126         return;
127     }
128 
129     hal_cipher_read_reg(sys_addr, &crg_value);
130     crg_value |= KLAD_CRG_RESET_BIT;   /* reset */
131     crg_value |= KLAD_CRG_CLOCK_BIT;   /* set the bit 1, clock opened */
132     hal_cipher_write_reg(sys_addr, crg_value);
133 
134     /* clock select and cancel reset 0x30100. */
135     crg_value &= (~KLAD_CRG_RESET_BIT); /* cancel reset */
136     crg_value |= KLAD_CRG_CLOCK_BIT;    /* set the bit 1, clock opened */
137     hal_cipher_write_reg(sys_addr, crg_value);
138 
139     crypto_iounmap(sys_addr, KLAD_BASE_BUF_SIZE);
140 }
141 
drv_cipher_klad_init(hi_void)142 hi_s32 drv_cipher_klad_init(hi_void)
143 {
144     hi_s32 ret;
145 
146     g_cipher_klad_base = crypto_ioremap_nocache(KLAD_REG_BASE_ADDR_PHY, KLAD_BASE_BUF_SIZE);
147     if (g_cipher_klad_base == HI_NULL) {
148         hi_log_error("ERROR: osal_ioremap_nocache for KLAD failed!!\n");
149         return HI_ERR_CIPHER_FAILED_MEM;
150     }
151 
152     ret = hal_efuse_otp_init();
153     if (ret != HI_SUCCESS) {
154         crypto_iounmap(g_cipher_klad_base, KLAD_BASE_BUF_SIZE);
155         return ret;
156     }
157 
158     hal_cipher_klad_init();
159 
160     return HI_SUCCESS;
161 }
162 
drv_cipher_klad_deinit(hi_void)163 hi_void drv_cipher_klad_deinit(hi_void)
164 {
165     hi_u8 *local_efuse_otp_reg_base = HI_NULL;
166 
167     if (g_cipher_klad_base != HI_NULL) {
168         crypto_iounmap(g_cipher_klad_base, KLAD_BASE_BUF_SIZE);
169         g_cipher_klad_base = HI_NULL;
170     }
171 
172     local_efuse_otp_reg_base = hal_efuse_otp_get_reg_base();
173     if (local_efuse_otp_reg_base != HI_NULL) {
174         crypto_iounmap(local_efuse_otp_reg_base, KLAD_BASE_BUF_SIZE);
175         local_efuse_otp_reg_base = HI_NULL;
176         hal_efuse_otp_set_reg_base(local_efuse_otp_reg_base);
177     }
178 
179     return;
180 }
181 
drv_cipher_inverse_data(hi_u8 * data,hi_u32 len)182 static hi_void drv_cipher_inverse_data(hi_u8 *data, hi_u32 len)
183 {
184     hi_u32 i;
185     hi_u8 ch;
186 
187     for (i = 0; i < len / MUL_VAL_2; i++) {
188         ch = data[i];
189         data[i] = data[len - i - BOUND_VAL_1];
190         data[len - i - BOUND_VAL_1] = ch;
191     }
192 }
193 
194 /* load aes or rsa clean key to klad. */
drv_cipher_klad_load_key(hi_u32 chn_id,hi_cipher_ca_type root_key,hi_cipher_klad_target target,const hi_u8 * data_in,hi_u32 key_len)195 hi_s32 drv_cipher_klad_load_key(hi_u32 chn_id,
196     hi_cipher_ca_type root_key, hi_cipher_klad_target target, const hi_u8 *data_in, hi_u32 key_len)
197 {
198     hi_s32 ret;
199     hi_u32 i, otp_id;
200     hi_u32 key[AES_BLOCK_SIZE / WORD_WIDTH] = {0};
201 
202     hi_log_chk_param_return((root_key < HI_CIPHER_KEY_SRC_KLAD_1) || (root_key > HI_CIPHER_KEY_SRC_KLAD_3));
203     hi_log_chk_param_return(target >= HI_CIPHER_KLAD_TARGET_BUTT);
204     hi_log_chk_param_return(data_in == HI_NULL);
205     hi_log_chk_param_return(((key_len % AES_BLOCK_SIZE) != 0) || (key_len == 0));
206 
207     otp_id = root_key - HI_CIPHER_KEY_SRC_KLAD_1 + BOUND_VAL_1;
208 
209     ret = hal_cipher_klad_config(chn_id, otp_id, target, HI_TRUE);
210     if (ret != HI_SUCCESS) {
211         hi_log_error("Error: cipher klad config failed!\n");
212         return ret;
213     }
214 
215     for (i = 0; i < key_len / AES_BLOCK_SIZE; i++) {
216         if (memcpy_s(key, sizeof(key), data_in + i * AES_BLOCK_SIZE, AES_BLOCK_SIZE) != EOK) {
217             hi_log_print_func_err(memcpy_s, HI_ERR_CIPHER_MEMCPY_S_FAILED);
218             return HI_ERR_CIPHER_MEMCPY_S_FAILED;
219         }
220         hal_cipher_set_klad_data(key, sizeof(key) / WORD_WIDTH);
221         hal_cipher_start_klad(i);
222         ret = hal_cipher_wait_klad_done();
223         if (ret != HI_SUCCESS) {
224             hi_log_error("Error: cipher klad wait done failed!\n");
225             (hi_void)memset_s(key, sizeof(key), 0, sizeof(key));
226             return ret;
227         }
228     }
229 
230     (hi_void)memset_s(key, sizeof(key), 0, sizeof(key));
231     return HI_SUCCESS;
232 }
233 
drv_cipher_klad_encrypt_key(hi_cipher_ca_type root_key,hi_cipher_klad_target target,hi_u8 * clean_key,hi_u8 * encrypt_key,hi_u32 key_len)234 hi_s32 drv_cipher_klad_encrypt_key(hi_cipher_ca_type root_key,
235     hi_cipher_klad_target target, hi_u8 *clean_key, hi_u8 *encrypt_key, hi_u32 key_len)
236 {
237     hi_s32 ret;
238     hi_u32 otp_id;
239 
240     hi_log_chk_param_return((root_key < HI_CIPHER_KEY_SRC_KLAD_1) || (root_key >= HI_CIPHER_KEY_SRC_BUTT));
241     hi_log_chk_param_return(target >= HI_CIPHER_KLAD_TARGET_BUTT);
242     hi_log_chk_param_return((clean_key == HI_NULL) || (encrypt_key == HI_NULL));
243     hi_log_chk_param_return(key_len != AES_BLOCK_SIZE);
244 
245     otp_id = root_key - HI_CIPHER_KEY_SRC_KLAD_1 + BOUND_VAL_1;
246 
247     ret = hal_cipher_klad_config(0, otp_id, HI_CIPHER_KLAD_TARGET_AES, HI_FALSE);
248     if (ret != HI_SUCCESS) {
249         hi_log_error("Error: cipher klad config failed!\n");
250         return ret;
251     }
252 
253     if (target == HI_CIPHER_KLAD_TARGET_RSA) {
254         drv_cipher_inverse_data(clean_key, key_len);
255     }
256 
257     hal_cipher_set_klad_data((hi_u32 *)clean_key, key_len / WORD_WIDTH);
258     hal_cipher_start_klad(0);
259     ret = hal_cipher_wait_klad_done();
260     if (ret != HI_SUCCESS) {
261         hi_log_error("Error: cipher klad wait done failed!\n");
262         return ret;
263     }
264     hal_cipher_get_klad_data((hi_u32 *)encrypt_key, key_len / WORD_WIDTH);
265 
266     return HI_SUCCESS;
267 }
268 
269