blob: 2f7cdc5accc87953d031f6cee62f628d57e8b522 [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>
37
38extern void dsb(void);
39
40/*
41 * Function to reset the crypto engine.
42 */
43
44void crypto_eng_reset(void)
45{
46 return;
47}
48
49/*
50 * Function to initialize the crypto engine for a new session. It enables the
51 * auto shutdown feature of CRYPTO and mask various interrupts since we use
52 * polling. We are not using DMOV now.
53 */
54
55void crypto_eng_init(void)
56{
57 unsigned int val;
58 val = (AUTO_SHUTDOWN_EN | MASK_ERR_INTR | MASK_DIN_INTR |
Ajay Dudanib01e5062011-12-03 23:23:42 -080059 MASK_DOUT_INTR | HIGH_SPD_IN_EN_N | HIGH_SPD_OUT_EN_N);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070060
61 val |= MASK_OP_DONE_INTR;
62
Ajay Dudanib01e5062011-12-03 23:23:42 -080063 wr_ce(val, CRYPTO_CONFIG);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070064}
65
66/*
67 * Function to set various SHAx registers in CRYPTO based on algorithm type.
68 */
69
Ajay Dudanib01e5062011-12-03 23:23:42 -080070void
71crypto_set_sha_ctx(void *ctx_ptr, unsigned int bytes_to_write,
72 crypto_auth_alg_type auth_alg, bool first, bool last)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070073{
Ajay Dudanib01e5062011-12-03 23:23:42 -080074 crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx *) ctx_ptr;
75 crypto_SHA256_ctx *sha256_ctx = (crypto_SHA256_ctx *) ctx_ptr;
76 unsigned int i = 0;
77 unsigned int iv_len = 0;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070078 unsigned int *auth_iv;
79 unsigned int seg_cfg_val;
80
81 seg_cfg_val = SEG_CFG_AUTH_ALG_SHA;
82
Ajay Dudanib01e5062011-12-03 23:23:42 -080083 if (auth_alg == CRYPTO_AUTH_ALG_SHA1) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070084 seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA1;
85
Ajay Dudanib01e5062011-12-03 23:23:42 -080086 if (last) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070087 seg_cfg_val |= SEG_CFG_LAST;
88 }
89
90 iv_len = SHA1_INIT_VECTOR_SIZE;
91 auth_iv = sha1_ctx->auth_iv;
Ajay Dudanib01e5062011-12-03 23:23:42 -080092 } else if (auth_alg == CRYPTO_AUTH_ALG_SHA256) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070093 seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA256;
94
Ajay Dudanib01e5062011-12-03 23:23:42 -080095 if (last) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -070096 seg_cfg_val |= SEG_CFG_LAST;
97 }
98
99 iv_len = SHA256_INIT_VECTOR_SIZE;
100 auth_iv = sha256_ctx->auth_iv;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800101 } else {
102 dprintf(CRITICAL,
103 "crypto_set_sha_ctx invalid auth algorithm\n");
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700104 return;
105 }
106
Ajay Dudanib01e5062011-12-03 23:23:42 -0800107 for (i = 0; i < iv_len; i++) {
108 wr_ce(*(auth_iv + i), CRYPTO_AUTH_IVn(i));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700109 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800110 wr_ce(seg_cfg_val, CRYPTO_AUTH_SEG_CFG);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700111
112 /* Typecast with crypto_SHA1_ctx because offset of auth_bytecnt in both
113 crypto_SHA1_ctx and crypto_SHA256_ctx are same */
114
Ajay Dudanib01e5062011-12-03 23:23:42 -0800115 wr_ce(((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[0],
116 CRYPTO_AUTH_BYTECNTn(0));
117 wr_ce(((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[1],
118 CRYPTO_AUTH_BYTECNTn(1));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700119
Ajay Dudanib01e5062011-12-03 23:23:42 -0800120 wr_ce(bytes_to_write, CRYPTO_AUTH_SEG_SIZE);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700121
Ajay Dudanib01e5062011-12-03 23:23:42 -0800122 wr_ce(bytes_to_write, CRYPTO_SEG_SIZE);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700123
124 /*
125 * Ensure previous instructions (any writes to config registers)
126 * are completed.
127 *
128 * TODO: Revisit dsb.
129 */
130 dsb();
131
Ajay Dudanib01e5062011-12-03 23:23:42 -0800132 wr_ce(GOPROC_GO, CRYPTO_GOPROC);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700133
134 return;
135}
136
137/*
138 * Function to send data to CRYPTO. This is non-DMOV implementation and uses
139 * polling to send the requested amount of data.
140 */
141
Ajay Dudanib01e5062011-12-03 23:23:42 -0800142void
143crypto_send_data(void *ctx_ptr, unsigned char *data_ptr,
144 unsigned int buff_size, unsigned int bytes_to_write,
145 unsigned int *ret_status)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700146{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800147 crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx *) ctx_ptr;
148 unsigned int bytes_left = 0;
149 unsigned int i = 0;
150 unsigned int ce_status = 0;
151 unsigned int ce_err_bmsk = 0;
152 unsigned int is_not_aligned = FALSE;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700153 unsigned char data[4];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800154 unsigned char *buff_ptr = data_ptr;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700155
156 /* Check if the buff_ptr is aligned */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800157 if (!(IS_ALIGNED(buff_ptr))) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700158 is_not_aligned = TRUE;
159 }
160
161 /* Fill the saved_buff with data from buff_ptr. First we have to write
162 all the data from the saved_buff and then we will write data from
163 buff_ptr. We will update bytes_left and buff_ptr in the while loop
164 once are done writing all the data from saved_buff. */
165
Ajay Dudanib01e5062011-12-03 23:23:42 -0800166 if (sha1_ctx->saved_buff_indx != 0) {
167 memcpy(sha1_ctx->saved_buff + sha1_ctx->saved_buff_indx,
168 buff_ptr,
169 (((buff_size + sha1_ctx->saved_buff_indx) <=
170 CRYPTO_SHA_BLOCK_SIZE)
171 ? buff_size : (CRYPTO_SHA_BLOCK_SIZE -
172 sha1_ctx->saved_buff_indx)));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700173
Ajay Dudanib01e5062011-12-03 23:23:42 -0800174 if (bytes_to_write >= CRYPTO_SHA_BLOCK_SIZE) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700175 bytes_left = CRYPTO_SHA_BLOCK_SIZE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800176 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700177 bytes_left = bytes_to_write;
178 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800179 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700180 bytes_left = bytes_to_write;
181 }
182
183 /* Error bitmask to check crypto engine status */
184 ce_err_bmsk = (SW_ERR | DIN_RDY | DIN_SIZE_AVAIL);
185
Ajay Dudanib01e5062011-12-03 23:23:42 -0800186 while (bytes_left >= 4) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700187 ce_status = rd_ce(CRYPTO_STATUS);
188 ce_status &= ce_err_bmsk;
189
Ajay Dudanib01e5062011-12-03 23:23:42 -0800190 if (ce_status & SW_ERR) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700191 /* If there is SW_ERR, reset the engine */
192 crypto_eng_reset();
193 *ret_status = CRYPTO_ERR_FAIL;
194 dprintf(CRITICAL, "crypto_send_data sw error\n");
195 return;
196 }
197
198 /* We can write data now - 4 bytes at a time in network byte order */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800199 if ((ce_status & DIN_RDY)
200 && ((ce_status & DIN_SIZE_AVAIL) >= 4)) {
201 if (sha1_ctx->saved_buff_indx != 0) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700202 /* Write from saved_buff */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800203 wr_ce(htonl
204 (*
205 ((unsigned int *)(sha1_ctx->saved_buff) +
206 i)), CRYPTO_DATA_IN);
207 } else {
208 if (!is_not_aligned) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700209 /* Write from buff_ptr aligned */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800210 wr_ce(htonl
211 (*((unsigned int *)buff_ptr + i)),
212 CRYPTO_DATA_IN);
213 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700214 /* If buff_ptr is not aligned write byte by byte */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800215 data[0] = *(buff_ptr + i);
216 data[1] = *(buff_ptr + i + 1);
217 data[2] = *(buff_ptr + i + 2);
218 data[3] = *(buff_ptr + i + 3);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700219 /* i will incremented by 1 in outside block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800220 i += 3;
221 wr_ce(htonl(*(unsigned int *)data),
222 CRYPTO_DATA_IN);
223 memset(data, 0, 4);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700224 }
225 }
226 i++;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800227 bytes_left -= 4;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700228
229 /* Check if we have written from saved_buff. Adjust buff_ptr and
230 bytes_left accordingly */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800231 if ((sha1_ctx->saved_buff_indx != 0)
232 && (bytes_left == 0)
233 && (bytes_to_write > CRYPTO_SHA_BLOCK_SIZE)) {
234 bytes_left =
235 (bytes_to_write - CRYPTO_SHA_BLOCK_SIZE);
236 buff_ptr =
237 (unsigned char *)((unsigned char *)data_ptr
238 + CRYPTO_SHA_BLOCK_SIZE -
239 sha1_ctx->
240 saved_buff_indx);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700241 i = 0;
242 sha1_ctx->saved_buff_indx = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800243 if (!(IS_ALIGNED(buff_ptr))) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700244 is_not_aligned = TRUE;
245 }
246 }
247 }
248 }
249
250 /* We might have bytes_left < 4. Write them now if available */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800251 if (bytes_left) {
252 memset(data, 0, sizeof(unsigned int));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700253
Ajay Dudanib01e5062011-12-03 23:23:42 -0800254 if (sha1_ctx->saved_buff_indx)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700255 buff_ptr = (sha1_ctx->saved_buff + bytes_to_write - 1);
256 else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800257 buff_ptr =
258 (((unsigned char *)data_ptr) + buff_size - 1);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700259
Ajay Dudanib01e5062011-12-03 23:23:42 -0800260 for (i = 0; i < bytes_left; i++) {
261 data[3 - i] = *(buff_ptr - bytes_left + i + 1);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700262 }
263
264 ce_status = rd_ce(CRYPTO_STATUS);
265 ce_status &= ce_err_bmsk;
266
Ajay Dudanib01e5062011-12-03 23:23:42 -0800267 if (ce_status & SW_ERR) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700268 crypto_eng_reset();
269 *ret_status = CRYPTO_ERR_FAIL;
270 dprintf(CRITICAL, "crypto_send_data sw error 2\n");
271 return;
272 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800273 if ((ce_status & DIN_RDY)
274 && ((ce_status & DIN_SIZE_AVAIL) >= 4)) {
275 wr_ce(*(unsigned int *)data, CRYPTO_DATA_IN);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700276 }
277 }
278 *ret_status = CRYPTO_ERR_NONE;
279 return;
280}
281
282/*
283 * Function to get digest from CRYPTO. We poll for AUTH_DONE from CRYPTO.
284 */
285
Ajay Dudanib01e5062011-12-03 23:23:42 -0800286void
287crypto_get_digest(unsigned char *digest_ptr, unsigned int *ret_status,
288 crypto_auth_alg_type auth_alg, bool last)
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700289{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800290 unsigned int ce_status = 0;
291 unsigned int ce_err_bmsk = 0;
292 unsigned int i = 0;
293 unsigned int digest_len = 0;
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700294
295 ce_err_bmsk = (OPERATION_DONE | SW_ERR);
296
Ajay Dudanib01e5062011-12-03 23:23:42 -0800297 do {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700298 ce_status = rd_ce(CRYPTO_STATUS);
299 ce_status &= ce_err_bmsk;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800300 }
301 while (ce_status == 0);
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700302
Ajay Dudanib01e5062011-12-03 23:23:42 -0800303 if (ce_status & SW_ERR) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700304 crypto_eng_reset();
305 *ret_status = CRYPTO_ERR_FAIL;
306 dprintf(CRITICAL, "crypto_get_digest sw error\n");
307 return;
308 }
309
310 /* Digest length depends on auth_alg */
311
Ajay Dudanib01e5062011-12-03 23:23:42 -0800312 if (auth_alg == CRYPTO_AUTH_ALG_SHA1) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700313 digest_len = SHA1_INIT_VECTOR_SIZE;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800314 } else if (auth_alg == CRYPTO_AUTH_ALG_SHA256) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700315 digest_len = SHA256_INIT_VECTOR_SIZE;
316 }
317
318 /* Retrieve digest from CRYPTO */
319
Ajay Dudanib01e5062011-12-03 23:23:42 -0800320 for (i = 0; i < digest_len; i++) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700321 unsigned int auth_iv = rd_ce(CRYPTO_AUTH_IVn(i));
322
Ajay Dudanib01e5062011-12-03 23:23:42 -0800323 if (last) {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700324 *((unsigned int *)digest_ptr + i) = htonl(auth_iv);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800325 } else {
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700326 *((unsigned int *)digest_ptr + i) = auth_iv;
327 }
328 }
329 *ret_status = CRYPTO_ERR_NONE;
330 return;
331}
332
333/* Function to restore auth_bytecnt registers for ctx_ptr */
334
335void crypto_get_ctx(void *ctx_ptr)
336{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800337 ((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[0] =
338 rd_ce(CRYPTO_AUTH_BYTECNTn(0));
339 ((crypto_SHA1_ctx *) ctx_ptr)->auth_bytecnt[1] =
340 rd_ce(CRYPTO_AUTH_BYTECNTn(1));
Shashank Mittal1fcde7a2011-07-25 13:41:50 -0700341 return;
342}