xref: /arm-trusted-firmware/plat/nvidia/tegra/soc/t186/drivers/se/se.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <drivers/delay_timer.h>
9*91f16700Schasinglulu #include <errno.h>
10*91f16700Schasinglulu #include <string.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <bpmp_ipc.h>
13*91f16700Schasinglulu #include <pmc.h>
14*91f16700Schasinglulu #include <security_engine.h>
15*91f16700Schasinglulu #include <tegra_private.h>
16*91f16700Schasinglulu 
17*91f16700Schasinglulu #include "se_private.h"
18*91f16700Schasinglulu 
19*91f16700Schasinglulu /*******************************************************************************
20*91f16700Schasinglulu  * Constants and Macros
21*91f16700Schasinglulu  ******************************************************************************/
22*91f16700Schasinglulu #define SE0_MAX_BUSY_TIMEOUT_MS		U(100)	/* 100ms */
23*91f16700Schasinglulu #define BYTES_IN_WORD			U(4)
24*91f16700Schasinglulu #define SHA256_MAX_HASH_RESULT		U(7)
25*91f16700Schasinglulu #define SHA256_DST_SIZE			U(32)
26*91f16700Schasinglulu #define SHA_FIRST_OP			U(1)
27*91f16700Schasinglulu #define MAX_SHA_ENGINE_CHUNK_SIZE	U(0xFFFFFF)
28*91f16700Schasinglulu #define SHA256_MSG_LENGTH_ONETIME	U(0xffff)
29*91f16700Schasinglulu 
30*91f16700Schasinglulu /*
31*91f16700Schasinglulu  * Check that SE operation has completed after kickoff
32*91f16700Schasinglulu  * This function is invoked after an SE operation has been started,
33*91f16700Schasinglulu  * and it checks the following conditions:
34*91f16700Schasinglulu  * 1. SE0_INT_STATUS = SE0_OP_DONE
35*91f16700Schasinglulu  * 2. SE0_STATUS = IDLE
36*91f16700Schasinglulu  * 3. SE0_ERR_STATUS is clean.
37*91f16700Schasinglulu  */
38*91f16700Schasinglulu static int32_t tegra_se_operation_complete(void)
39*91f16700Schasinglulu {
40*91f16700Schasinglulu 	uint32_t val = 0U;
41*91f16700Schasinglulu 
42*91f16700Schasinglulu 	/* Read SE0 interrupt register to ensure H/W operation complete */
43*91f16700Schasinglulu 	val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
44*91f16700Schasinglulu 	if (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) {
45*91f16700Schasinglulu 		ERROR("%s: Engine busy state too many times! val = 0x%x\n",
46*91f16700Schasinglulu 			__func__, val);
47*91f16700Schasinglulu 		return -ETIMEDOUT;
48*91f16700Schasinglulu 	}
49*91f16700Schasinglulu 
50*91f16700Schasinglulu 	/* Read SE0 status idle to ensure H/W operation complete */
51*91f16700Schasinglulu 	val = tegra_se_read_32(SE0_SHA_STATUS_0);
52*91f16700Schasinglulu 	if (val != SE0_SHA_STATUS_IDLE) {
53*91f16700Schasinglulu 		ERROR("%s: Idle state timeout! val = 0x%x\n", __func__,
54*91f16700Schasinglulu 			val);
55*91f16700Schasinglulu 		return -ETIMEDOUT;
56*91f16700Schasinglulu 	}
57*91f16700Schasinglulu 
58*91f16700Schasinglulu 	/* Ensure that no errors are thrown during operation */
59*91f16700Schasinglulu 	val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET);
60*91f16700Schasinglulu 	if (val != SE0_ERR_STATUS_CLEAR) {
61*91f16700Schasinglulu 		ERROR("%s: Error during SE operation! val = 0x%x",
62*91f16700Schasinglulu 			__func__, val);
63*91f16700Schasinglulu 		return -ENOTSUP;
64*91f16700Schasinglulu 	}
65*91f16700Schasinglulu 
66*91f16700Schasinglulu 	return 0;
67*91f16700Schasinglulu }
68*91f16700Schasinglulu 
69*91f16700Schasinglulu /*
70*91f16700Schasinglulu  * Security engine primitive normal operations
71*91f16700Schasinglulu  */
72*91f16700Schasinglulu static int32_t tegra_se_start_normal_operation(uint64_t src_addr,
73*91f16700Schasinglulu 		uint32_t nbytes, uint32_t last_buf, uint32_t src_len_inbytes)
74*91f16700Schasinglulu {
75*91f16700Schasinglulu 	int32_t ret = 0;
76*91f16700Schasinglulu 	uint32_t val = 0U;
77*91f16700Schasinglulu 	uint32_t src_in_lo;
78*91f16700Schasinglulu 	uint32_t src_in_msb;
79*91f16700Schasinglulu 	uint32_t src_in_hi;
80*91f16700Schasinglulu 
81*91f16700Schasinglulu 	if ((src_addr == 0UL) || (nbytes == 0U))
82*91f16700Schasinglulu 		return -EINVAL;
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	src_in_lo = (uint32_t)src_addr;
85*91f16700Schasinglulu 	src_in_msb = ((uint32_t)(src_addr >> 32U) & 0xffU);
86*91f16700Schasinglulu 	src_in_hi = ((src_in_msb << SE0_IN_HI_ADDR_HI_0_MSB_SHIFT) |
87*91f16700Schasinglulu 				(nbytes & 0xffffffU));
88*91f16700Schasinglulu 
89*91f16700Schasinglulu 	/* set SRC_IN_ADDR_LO and SRC_IN_ADDR_HI*/
90*91f16700Schasinglulu 	tegra_se_write_32(SE0_IN_ADDR, src_in_lo);
91*91f16700Schasinglulu 	tegra_se_write_32(SE0_IN_HI_ADDR_HI, src_in_hi);
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 	val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
94*91f16700Schasinglulu 	if (val > 0U) {
95*91f16700Schasinglulu 		tegra_se_write_32(SE0_INT_STATUS_REG_OFFSET, 0x00000U);
96*91f16700Schasinglulu 	}
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	/* Enable SHA interrupt for SE0 Operation */
99*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_INT_ENABLE, 0x1aU);
100*91f16700Schasinglulu 
101*91f16700Schasinglulu 	/* flush to DRAM for SE to use the updated contents */
102*91f16700Schasinglulu 	flush_dcache_range(src_addr, src_len_inbytes);
103*91f16700Schasinglulu 
104*91f16700Schasinglulu 	/* Start SHA256 operation */
105*91f16700Schasinglulu 	if (last_buf == 1U) {
106*91f16700Schasinglulu 		tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START |
107*91f16700Schasinglulu 				SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD);
108*91f16700Schasinglulu 	} else {
109*91f16700Schasinglulu 		tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START);
110*91f16700Schasinglulu 	}
111*91f16700Schasinglulu 
112*91f16700Schasinglulu 	/* Wait for SE-operation to finish */
113*91f16700Schasinglulu 	udelay(SE0_MAX_BUSY_TIMEOUT_MS * 100U);
114*91f16700Schasinglulu 
115*91f16700Schasinglulu 	/* Check SE0 operation status */
116*91f16700Schasinglulu 	ret = tegra_se_operation_complete();
117*91f16700Schasinglulu 	if (ret != 0) {
118*91f16700Schasinglulu 		ERROR("SE operation complete Failed! 0x%x", ret);
119*91f16700Schasinglulu 		return ret;
120*91f16700Schasinglulu 	}
121*91f16700Schasinglulu 
122*91f16700Schasinglulu 	return 0;
123*91f16700Schasinglulu }
124*91f16700Schasinglulu 
125*91f16700Schasinglulu static int32_t tegra_se_calculate_sha256_hash(uint64_t src_addr,
126*91f16700Schasinglulu 						uint32_t src_len_inbyte)
127*91f16700Schasinglulu {
128*91f16700Schasinglulu 	uint32_t val, last_buf, i;
129*91f16700Schasinglulu 	int32_t ret = 0;
130*91f16700Schasinglulu 	uint32_t operations;
131*91f16700Schasinglulu 	uint64_t src_len_inbits;
132*91f16700Schasinglulu 	uint32_t len_bits_msb;
133*91f16700Schasinglulu 	uint32_t len_bits_lsb;
134*91f16700Schasinglulu 	uint32_t number_of_operations, max_bytes, bytes_left, remaining_bytes;
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 	if (src_len_inbyte > MAX_SHA_ENGINE_CHUNK_SIZE) {
137*91f16700Schasinglulu 		ERROR("SHA input chunk size too big: 0x%x\n", src_len_inbyte);
138*91f16700Schasinglulu 		return -EINVAL;
139*91f16700Schasinglulu 	}
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 	if (src_addr == 0UL) {
142*91f16700Schasinglulu 		return -EINVAL;
143*91f16700Schasinglulu 	}
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 	/* number of bytes per operation */
146*91f16700Schasinglulu 	max_bytes = SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME;
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	src_len_inbits = src_len_inbyte * 8U;
149*91f16700Schasinglulu 	len_bits_msb = (uint32_t)(src_len_inbits >> 32U);
150*91f16700Schasinglulu 	len_bits_lsb = (uint32_t)(src_len_inbits & 0xFFFFFFFF);
151*91f16700Schasinglulu 
152*91f16700Schasinglulu 	/* program SE0_CONFIG for SHA256 operation */
153*91f16700Schasinglulu 	val = SE0_CONFIG_ENC_ALG_SHA | SE0_CONFIG_ENC_MODE_SHA256 |
154*91f16700Schasinglulu 		SE0_CONFIG_DEC_ALG_NOP | SE0_CONFIG_DST_HASHREG;
155*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_CONFIG, val);
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	/* set SE0_SHA_MSG_LENGTH registers */
158*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LENGTH_0, len_bits_lsb);
159*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
160*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LENGTH_1, len_bits_msb);
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	/* zero out unused SE0_SHA_MSG_LENGTH and SE0_SHA_MSG_LEFT */
163*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LENGTH_2, 0U);
164*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LENGTH_3, 0U);
165*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LEFT_1, 0U);
166*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LEFT_2, 0U);
167*91f16700Schasinglulu 	tegra_se_write_32(SE0_SHA_MSG_LEFT_3, 0U);
168*91f16700Schasinglulu 
169*91f16700Schasinglulu 	number_of_operations = src_len_inbyte / max_bytes;
170*91f16700Schasinglulu 	remaining_bytes = src_len_inbyte % max_bytes;
171*91f16700Schasinglulu 	if (remaining_bytes > 0U) {
172*91f16700Schasinglulu 		number_of_operations += 1U;
173*91f16700Schasinglulu 	}
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 	/*
176*91f16700Schasinglulu 	 * 1. Operations == 1:	program SE0_SHA_TASK register to initiate SHA256
177*91f16700Schasinglulu 	 *			hash generation by setting
178*91f16700Schasinglulu 	 *			1(SE0_SHA_CONFIG_HW_INIT_HASH) to SE0_SHA_TASK
179*91f16700Schasinglulu 	 *			and start SHA256-normal operation.
180*91f16700Schasinglulu 	 * 2. 1 < Operations < number_of_operations: program SE0_SHA_TASK to
181*91f16700Schasinglulu 	 *			0(SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE) to load
182*91f16700Schasinglulu 	 *			intermediate SHA256 digest result from
183*91f16700Schasinglulu 	 *			HASH_RESULT register to continue SHA256
184*91f16700Schasinglulu 	 *			generation and start SHA256-normal operation.
185*91f16700Schasinglulu 	 * 3. Operations == number_of_operations: continue with step 2 and set
186*91f16700Schasinglulu 	 *			max_bytes to bytes_left to process final
187*91f16700Schasinglulu 	 *			hash-result generation and
188*91f16700Schasinglulu 	 *			start SHA256-normal operation.
189*91f16700Schasinglulu 	 */
190*91f16700Schasinglulu 	bytes_left = src_len_inbyte;
191*91f16700Schasinglulu 	for (operations = 1U; operations <= number_of_operations;
192*91f16700Schasinglulu 								operations++) {
193*91f16700Schasinglulu 		if (operations == SHA_FIRST_OP) {
194*91f16700Schasinglulu 			val = SE0_SHA_CONFIG_HW_INIT_HASH;
195*91f16700Schasinglulu 		} else {
196*91f16700Schasinglulu 			/* Load intermediate SHA digest result to
197*91f16700Schasinglulu 			 * SHA:HASH_RESULT(0..7) to continue the SHA
198*91f16700Schasinglulu 			 * calculation and tell the SHA engine to use it.
199*91f16700Schasinglulu 			 */
200*91f16700Schasinglulu 			for (i = 0U; (i / BYTES_IN_WORD) <=
201*91f16700Schasinglulu 				SHA256_MAX_HASH_RESULT; i += BYTES_IN_WORD) {
202*91f16700Schasinglulu 				val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 +
203*91f16700Schasinglulu 									i);
204*91f16700Schasinglulu 				tegra_se_write_32(SE0_SHA_HASH_RESULT_0 + i,
205*91f16700Schasinglulu 									val);
206*91f16700Schasinglulu 			}
207*91f16700Schasinglulu 			val = SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE;
208*91f16700Schasinglulu 			if (len_bits_lsb <= (max_bytes * 8U)) {
209*91f16700Schasinglulu 				len_bits_lsb = (remaining_bytes * 8U);
210*91f16700Schasinglulu 			} else {
211*91f16700Schasinglulu 				len_bits_lsb -= (max_bytes * 8U);
212*91f16700Schasinglulu 			}
213*91f16700Schasinglulu 			tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
214*91f16700Schasinglulu 		}
215*91f16700Schasinglulu 		tegra_se_write_32(SE0_SHA_TASK_CONFIG, val);
216*91f16700Schasinglulu 
217*91f16700Schasinglulu 		max_bytes = (SHA256_HASH_SIZE_BYTES *
218*91f16700Schasinglulu 						SHA256_MSG_LENGTH_ONETIME);
219*91f16700Schasinglulu 		if (bytes_left < max_bytes) {
220*91f16700Schasinglulu 			max_bytes = bytes_left;
221*91f16700Schasinglulu 			last_buf = 1U;
222*91f16700Schasinglulu 		} else {
223*91f16700Schasinglulu 			bytes_left = bytes_left - max_bytes;
224*91f16700Schasinglulu 			last_buf = 0U;
225*91f16700Schasinglulu 		}
226*91f16700Schasinglulu 		/* start operation */
227*91f16700Schasinglulu 		ret = tegra_se_start_normal_operation(src_addr, max_bytes,
228*91f16700Schasinglulu 					last_buf, src_len_inbyte);
229*91f16700Schasinglulu 		if (ret != 0) {
230*91f16700Schasinglulu 			ERROR("Error during SE operation! 0x%x", ret);
231*91f16700Schasinglulu 			return -EINVAL;
232*91f16700Schasinglulu 		}
233*91f16700Schasinglulu 	}
234*91f16700Schasinglulu 
235*91f16700Schasinglulu 	return ret;
236*91f16700Schasinglulu }
237*91f16700Schasinglulu 
238*91f16700Schasinglulu /*
239*91f16700Schasinglulu  * Handler to generate SHA256 and save SHA256 hash to PMC-Scratch register.
240*91f16700Schasinglulu  */
241*91f16700Schasinglulu int32_t tegra_se_save_sha256_hash(uint64_t bl31_base, uint32_t src_len_inbyte)
242*91f16700Schasinglulu {
243*91f16700Schasinglulu 	int32_t ret = 0;
244*91f16700Schasinglulu 	uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U, security;
245*91f16700Schasinglulu 
246*91f16700Schasinglulu 	/*
247*91f16700Schasinglulu 	 * Set SE_SOFT_SETTINGS=SE_SECURE to prevent NS process to change SE
248*91f16700Schasinglulu 	 * registers.
249*91f16700Schasinglulu 	 */
250*91f16700Schasinglulu 	security = tegra_se_read_32(SE0_SECURITY);
251*91f16700Schasinglulu 	tegra_se_write_32(SE0_SECURITY, security | SE0_SECURITY_SE_SOFT_SETTING);
252*91f16700Schasinglulu 
253*91f16700Schasinglulu 	ret = tegra_se_calculate_sha256_hash(bl31_base, src_len_inbyte);
254*91f16700Schasinglulu 	if (ret != 0L) {
255*91f16700Schasinglulu 		ERROR("%s: SHA256 generation failed\n", __func__);
256*91f16700Schasinglulu 		return ret;
257*91f16700Schasinglulu 	}
258*91f16700Schasinglulu 
259*91f16700Schasinglulu 	/*
260*91f16700Schasinglulu 	 * Reset SE_SECURE to previous value.
261*91f16700Schasinglulu 	 */
262*91f16700Schasinglulu 	tegra_se_write_32(SE0_SECURITY, security);
263*91f16700Schasinglulu 
264*91f16700Schasinglulu 	/* read SHA256_HASH_RESULT and save to PMC Scratch registers */
265*91f16700Schasinglulu 	scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START;
266*91f16700Schasinglulu 	while (scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END) {
267*91f16700Schasinglulu 
268*91f16700Schasinglulu 		val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset);
269*91f16700Schasinglulu 		mmio_write_32(TEGRA_SCRATCH_BASE + scratch_offset, val);
270*91f16700Schasinglulu 
271*91f16700Schasinglulu 		hash_offset += BYTES_IN_WORD;
272*91f16700Schasinglulu 		scratch_offset += BYTES_IN_WORD;
273*91f16700Schasinglulu 	}
274*91f16700Schasinglulu 
275*91f16700Schasinglulu 	return ret;
276*91f16700Schasinglulu }
277*91f16700Schasinglulu 
278