blob: aeeca5f17068036b0fb428929388347a15cbe4e8 [file] [log] [blame]
Shashank Mittal1fcde7a2011-07-25 13:41:50 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <string.h>
30#include <endian.h>
31#include <debug.h>
32#include <reg.h>
33#include <bits.h>
34#include <platform/iomap.h>
35#include <crypto4_eng.h>
36#include <crypto_hash.h>
Deepa Dinamani193874e2012-02-07 14:00:04 -080037#include <scm.h>
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070038
39extern void dsb(void);
40
41/*
42 * Function to reset the crypto engine.
43 */
44
45void crypto_eng_reset(void)
46{
47 return;
48}
49
Deepa Dinamani193874e2012-02-07 14:00:04 -080050
51/* Function to switch the CE1 context
52 * from register to ADM
53 */
54void crypto_eng_cleanup(void)
55{
56
57 unsigned int val;
58
59 enum ap_ce_channel_type chn = AP_CE_ADM_USE;
60 /* Make a SMC call to TZ to make CE1 use ADM interface for HLOS*/
61 val = switch_ce_chn_cmd(chn);
62 dprintf(INFO, "TZ channel swith returned %d\n", val);
63
64}
65
66
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070067/*
68 * Function to initialize the crypto engine for a new session. It enables the
69 * auto shutdown feature of CRYPTO and mask various interrupts since we use
70 * polling. We are not using DMOV now.
71 */
72
73void crypto_eng_init(void)
74{
75 unsigned int val;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070076
Deepa Dinamani193874e2012-02-07 14:00:04 -080077 enum ap_ce_channel_type chn = AP_CE_REGISTER_USE;
78 /* Make a SMC call to TZ to make CE1 use register interface */
79 val = switch_ce_chn_cmd(chn);
80 dprintf(INFO, "TZ channel swith returned %d\n", val);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070081
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070082}
83
84/*
85 * Function to set various SHAx registers in CRYPTO based on algorithm type.
86 */
87
Ajay Dudanib01e5062011-12-03 23:23:42 -080088void
89crypto_set_sha_ctx(void *ctx_ptr, unsigned int bytes_to_write,
90 crypto_auth_alg_type auth_alg, bool first, bool last)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070091{
Ajay Dudanib01e5062011-12-03 23:23:42 -080092 crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx *) ctx_ptr;
93 crypto_SHA256_ctx *sha256_ctx = (crypto_SHA256_ctx *) ctx_ptr;
94 unsigned int i = 0;
95 unsigned int iv_len = 0;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070096 unsigned int *auth_iv;
97 unsigned int seg_cfg_val;
98
99 seg_cfg_val = SEG_CFG_AUTH_ALG_SHA;
100
Ajay Dudanib01e5062011-12-03 23:23:42 -0800101 if (auth_alg == CRYPTO_AUTH_ALG_SHA1) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700102 seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA1;
103
Ajay Dudanib01e5062011-12-03 23:23:42 -0800104 if (last) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700105 seg_cfg_val |= SEG_CFG_LAST;
106 }
107
108 iv_len = SHA1_INIT_VECTOR_SIZE;
109 auth_iv = sha1_ctx->auth_iv;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800110 } else if (auth_alg == CRYPTO_AUTH_ALG_SHA256) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700111 seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA256;
112
Ajay Dudanib01e5062011-12-03 23:23:42 -0800113 if (last) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700114 seg_cfg_val |= SEG_CFG_LAST;
115 }
116
117 iv_len = SHA256_INIT_VECTOR_SIZE;
118 auth_iv = sha256_ctx->auth_iv;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800119 } else {
120 dprintf(CRITICAL,
121 "crypto_set_sha_ctx invalid auth algorithm\n");
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700122 return;
123 }
124
Ajay Dudanib01e5062011-12-03 23:23:42 -0800125 for (i = 0; i < iv_len; i++) {
126 wr_ce(*(auth_iv + i), CRYPTO_AUTH_IVn(i));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700127 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800128 wr_ce(seg_cfg_val, CRYPTO_AUTH_SEG_CFG);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700129
130 /* Typecast with crypto_SHA1_ctx because offset of auth_bytecnt in both
131 crypto_SHA1_ctx and crypto_SHA256_ctx are same */
132
Ajay Dudanib01e5062011-12-03 23:23:42 -0800133 wr_ce(((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[0],
134 CRYPTO_AUTH_BYTECNTn(0));
135 wr_ce(((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[1],
136 CRYPTO_AUTH_BYTECNTn(1));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700137
Ajay Dudanib01e5062011-12-03 23:23:42 -0800138 wr_ce(bytes_to_write, CRYPTO_AUTH_SEG_SIZE);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700139
Ajay Dudanib01e5062011-12-03 23:23:42 -0800140 wr_ce(bytes_to_write, CRYPTO_SEG_SIZE);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700141
142 /*
143 * Ensure previous instructions (any writes to config registers)
144 * are completed.
145 *
146 * TODO: Revisit dsb.
147 */
148 dsb();
149
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150 wr_ce(GOPROC_GO, CRYPTO_GOPROC);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700151
152 return;
153}
154
155/*
156 * Function to send data to CRYPTO. This is non-DMOV implementation and uses
157 * polling to send the requested amount of data.
158 */
159
Ajay Dudanib01e5062011-12-03 23:23:42 -0800160void
161crypto_send_data(void *ctx_ptr, unsigned char *data_ptr,
162 unsigned int buff_size, unsigned int bytes_to_write,
163 unsigned int *ret_status)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700164{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800165 crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx *) ctx_ptr;
166 unsigned int bytes_left = 0;
167 unsigned int i = 0;
168 unsigned int ce_status = 0;
169 unsigned int ce_err_bmsk = 0;
170 unsigned int is_not_aligned = FALSE;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700171 unsigned char data[4];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800172 unsigned char *buff_ptr = data_ptr;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700173
174 /* Check if the buff_ptr is aligned */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800175 if (!(IS_ALIGNED(buff_ptr))) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700176 is_not_aligned = TRUE;
177 }
178
179 /* Fill the saved_buff with data from buff_ptr. First we have to write
180 all the data from the saved_buff and then we will write data from
181 buff_ptr. We will update bytes_left and buff_ptr in the while loop
182 once are done writing all the data from saved_buff. */
183
Ajay Dudanib01e5062011-12-03 23:23:42 -0800184 if (sha1_ctx->saved_buff_indx != 0) {
185 memcpy(sha1_ctx->saved_buff + sha1_ctx->saved_buff_indx,
186 buff_ptr,
187 (((buff_size + sha1_ctx->saved_buff_indx) <=
188 CRYPTO_SHA_BLOCK_SIZE)
189 ? buff_size : (CRYPTO_SHA_BLOCK_SIZE -
190 sha1_ctx->saved_buff_indx)));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700191
Ajay Dudanib01e5062011-12-03 23:23:42 -0800192 if (bytes_to_write >= CRYPTO_SHA_BLOCK_SIZE) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700193 bytes_left = CRYPTO_SHA_BLOCK_SIZE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800194 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700195 bytes_left = bytes_to_write;
196 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800197 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700198 bytes_left = bytes_to_write;
199 }
200
201 /* Error bitmask to check crypto engine status */
202 ce_err_bmsk = (SW_ERR | DIN_RDY | DIN_SIZE_AVAIL);
203
Ajay Dudanib01e5062011-12-03 23:23:42 -0800204 while (bytes_left >= 4) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700205 ce_status = rd_ce(CRYPTO_STATUS);
206 ce_status &= ce_err_bmsk;
207
Ajay Dudanib01e5062011-12-03 23:23:42 -0800208 if (ce_status & SW_ERR) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700209 /* If there is SW_ERR, reset the engine */
210 crypto_eng_reset();
211 *ret_status = CRYPTO_ERR_FAIL;
212 dprintf(CRITICAL, "crypto_send_data sw error\n");
213 return;
214 }
215
216 /* We can write data now - 4 bytes at a time in network byte order */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800217 if ((ce_status & DIN_RDY)
218 && ((ce_status & DIN_SIZE_AVAIL) >= 4)) {
219 if (sha1_ctx->saved_buff_indx != 0) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700220 /* Write from saved_buff */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800221 wr_ce(htonl
222 (*
223 ((unsigned int *)(sha1_ctx->saved_buff) +
224 i)), CRYPTO_DATA_IN);
225 } else {
226 if (!is_not_aligned) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700227 /* Write from buff_ptr aligned */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800228 wr_ce(htonl
229 (*((unsigned int *)buff_ptr + i)),
230 CRYPTO_DATA_IN);
231 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700232 /* If buff_ptr is not aligned write byte by byte */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800233 data[0] = *(buff_ptr + i);
234 data[1] = *(buff_ptr + i + 1);
235 data[2] = *(buff_ptr + i + 2);
236 data[3] = *(buff_ptr + i + 3);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700237 /* i will incremented by 1 in outside block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800238 i += 3;
239 wr_ce(htonl(*(unsigned int *)data),
240 CRYPTO_DATA_IN);
241 memset(data, 0, 4);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700242 }
243 }
244 i++;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800245 bytes_left -= 4;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700246
247 /* Check if we have written from saved_buff. Adjust buff_ptr and
248 bytes_left accordingly */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800249 if ((sha1_ctx->saved_buff_indx != 0)
250 && (bytes_left == 0)
251 && (bytes_to_write > CRYPTO_SHA_BLOCK_SIZE)) {
252 bytes_left =
253 (bytes_to_write - CRYPTO_SHA_BLOCK_SIZE);
254 buff_ptr =
255 (unsigned char *)((unsigned char *)data_ptr
256 + CRYPTO_SHA_BLOCK_SIZE -
257 sha1_ctx->
258 saved_buff_indx);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700259 i = 0;
260 sha1_ctx->saved_buff_indx = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800261 if (!(IS_ALIGNED(buff_ptr))) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700262 is_not_aligned = TRUE;
263 }
264 }
265 }
266 }
267
268 /* We might have bytes_left < 4. Write them now if available */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800269 if (bytes_left) {
270 memset(data, 0, sizeof(unsigned int));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700271
Ajay Dudanib01e5062011-12-03 23:23:42 -0800272 if (sha1_ctx->saved_buff_indx)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700273 buff_ptr = (sha1_ctx->saved_buff + bytes_to_write - 1);
274 else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800275 buff_ptr =
276 (((unsigned char *)data_ptr) + buff_size - 1);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700277
Ajay Dudanib01e5062011-12-03 23:23:42 -0800278 for (i = 0; i < bytes_left; i++) {
279 data[3 - i] = *(buff_ptr - bytes_left + i + 1);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700280 }
281
282 ce_status = rd_ce(CRYPTO_STATUS);
283 ce_status &= ce_err_bmsk;
284
Ajay Dudanib01e5062011-12-03 23:23:42 -0800285 if (ce_status & SW_ERR) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700286 crypto_eng_reset();
287 *ret_status = CRYPTO_ERR_FAIL;
288 dprintf(CRITICAL, "crypto_send_data sw error 2\n");
289 return;
290 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800291 if ((ce_status & DIN_RDY)
292 && ((ce_status & DIN_SIZE_AVAIL) >= 4)) {
293 wr_ce(*(unsigned int *)data, CRYPTO_DATA_IN);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700294 }
295 }
296 *ret_status = CRYPTO_ERR_NONE;
297 return;
298}
299
300/*
301 * Function to get digest from CRYPTO. We poll for AUTH_DONE from CRYPTO.
302 */
303
Ajay Dudanib01e5062011-12-03 23:23:42 -0800304void
305crypto_get_digest(unsigned char *digest_ptr, unsigned int *ret_status,
306 crypto_auth_alg_type auth_alg, bool last)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700307{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800308 unsigned int ce_status = 0;
309 unsigned int ce_err_bmsk = 0;
310 unsigned int i = 0;
311 unsigned int digest_len = 0;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700312
313 ce_err_bmsk = (OPERATION_DONE | SW_ERR);
314
Ajay Dudanib01e5062011-12-03 23:23:42 -0800315 do {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700316 ce_status = rd_ce(CRYPTO_STATUS);
317 ce_status &= ce_err_bmsk;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800318 }
319 while (ce_status == 0);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700320
Ajay Dudanib01e5062011-12-03 23:23:42 -0800321 if (ce_status & SW_ERR) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700322 crypto_eng_reset();
323 *ret_status = CRYPTO_ERR_FAIL;
324 dprintf(CRITICAL, "crypto_get_digest sw error\n");
325 return;
326 }
327
328 /* Digest length depends on auth_alg */
329
Ajay Dudanib01e5062011-12-03 23:23:42 -0800330 if (auth_alg == CRYPTO_AUTH_ALG_SHA1) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700331 digest_len = SHA1_INIT_VECTOR_SIZE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800332 } else if (auth_alg == CRYPTO_AUTH_ALG_SHA256) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700333 digest_len = SHA256_INIT_VECTOR_SIZE;
334 }
335
336 /* Retrieve digest from CRYPTO */
337
Ajay Dudanib01e5062011-12-03 23:23:42 -0800338 for (i = 0; i < digest_len; i++) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700339 unsigned int auth_iv = rd_ce(CRYPTO_AUTH_IVn(i));
340
Ajay Dudanib01e5062011-12-03 23:23:42 -0800341 if (last) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700342 *((unsigned int *)digest_ptr + i) = htonl(auth_iv);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800343 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700344 *((unsigned int *)digest_ptr + i) = auth_iv;
345 }
346 }
347 *ret_status = CRYPTO_ERR_NONE;
348 return;
349}
350
351/* Function to restore auth_bytecnt registers for ctx_ptr */
352
353void crypto_get_ctx(void *ctx_ptr)
354{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800355 ((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[0] =
356 rd_ce(CRYPTO_AUTH_BYTECNTn(0));
357 ((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[1] =
358 rd_ce(CRYPTO_AUTH_BYTECNTn(1));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700359 return;
360}