xref: /optee_os/core/pta/stm32mp/bsec_pta.c (revision 4583de067b5da0cbcbdb341e7a4d9d0cdec2d033)
1*4583de06SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2*4583de06SGatien Chevallier /*
3*4583de06SGatien Chevallier  * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
4*4583de06SGatien Chevallier  */
5*4583de06SGatien Chevallier 
6*4583de06SGatien Chevallier #include <config.h>
7*4583de06SGatien Chevallier #include <drivers/stm32_bsec.h>
8*4583de06SGatien Chevallier #include <kernel/pseudo_ta.h>
9*4583de06SGatien Chevallier #include <kernel/user_access.h>
10*4583de06SGatien Chevallier #include <kernel/user_mode_ctx.h>
11*4583de06SGatien Chevallier #include <kernel/user_ta.h>
12*4583de06SGatien Chevallier #include <mm/vm.h>
13*4583de06SGatien Chevallier #include <pta_stm32mp_bsec.h>
14*4583de06SGatien Chevallier #include <string.h>
15*4583de06SGatien Chevallier #include <util.h>
16*4583de06SGatien Chevallier 
17*4583de06SGatien Chevallier static_assert(IS_ENABLED(CFG_STM32_BSEC));
18*4583de06SGatien Chevallier 
19*4583de06SGatien Chevallier #define PTA_NAME "bsec.pta"
20*4583de06SGatien Chevallier 
bsec_check_access(uint32_t otp_id)21*4583de06SGatien Chevallier static TEE_Result bsec_check_access(uint32_t otp_id)
22*4583de06SGatien Chevallier {
23*4583de06SGatien Chevallier 	if (!stm32_bsec_nsec_can_access_otp(otp_id))
24*4583de06SGatien Chevallier 		return TEE_ERROR_ACCESS_DENIED;
25*4583de06SGatien Chevallier 
26*4583de06SGatien Chevallier 	return TEE_SUCCESS;
27*4583de06SGatien Chevallier }
28*4583de06SGatien Chevallier 
bsec_read_mem(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])29*4583de06SGatien Chevallier static TEE_Result bsec_read_mem(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS])
30*4583de06SGatien Chevallier {
31*4583de06SGatien Chevallier 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
32*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
33*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE,
34*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE);
35*4583de06SGatien Chevallier 	uint32_t *buf = (uint32_t *)params[1].memref.buffer;
36*4583de06SGatien Chevallier 	uint32_t otp_start = 0;
37*4583de06SGatien Chevallier 	size_t otp_length = 0;
38*4583de06SGatien Chevallier 	uint32_t otp_id = 0;
39*4583de06SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
40*4583de06SGatien Chevallier 	size_t size = params[1].memref.size;
41*4583de06SGatien Chevallier 	bool locked = false;
42*4583de06SGatien Chevallier 	unsigned int otp_base_offset = params[0].value.a;
43*4583de06SGatien Chevallier 	unsigned int bsec_command = params[0].value.b;
44*4583de06SGatien Chevallier 
45*4583de06SGatien Chevallier 	if (pt != exp_pt || !buf || !size ||
46*4583de06SGatien Chevallier 	    !IS_ALIGNED_WITH_TYPE(params[1].memref.buffer, uint32_t))
47*4583de06SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
48*4583de06SGatien Chevallier 
49*4583de06SGatien Chevallier 	/* Check 32bits alignment */
50*4583de06SGatien Chevallier 	if (otp_base_offset % BSEC_BYTES_PER_WORD ||
51*4583de06SGatien Chevallier 	    size % BSEC_BYTES_PER_WORD)
52*4583de06SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
53*4583de06SGatien Chevallier 
54*4583de06SGatien Chevallier 	otp_start = otp_base_offset / BSEC_BYTES_PER_WORD;
55*4583de06SGatien Chevallier 	otp_length = size / BSEC_BYTES_PER_WORD;
56*4583de06SGatien Chevallier 
57*4583de06SGatien Chevallier 	for (otp_id = otp_start; otp_id < otp_start + otp_length;
58*4583de06SGatien Chevallier 	     otp_id++, buf++) {
59*4583de06SGatien Chevallier 		res = bsec_check_access(otp_id);
60*4583de06SGatien Chevallier 		switch (bsec_command) {
61*4583de06SGatien Chevallier 		case PTA_BSEC_SHADOW_ACCESS:
62*4583de06SGatien Chevallier 			if (res) {
63*4583de06SGatien Chevallier 				/* Force 0 when access is not allowed */
64*4583de06SGatien Chevallier 				*buf = 0x0;
65*4583de06SGatien Chevallier 				continue;
66*4583de06SGatien Chevallier 			}
67*4583de06SGatien Chevallier 			/* Read shadow register */
68*4583de06SGatien Chevallier 			res = stm32_bsec_read_otp(buf, otp_id);
69*4583de06SGatien Chevallier 			FMSG("Read shadow %"PRIu32" val: %#"PRIx32, otp_id,
70*4583de06SGatien Chevallier 			     *buf);
71*4583de06SGatien Chevallier 			break;
72*4583de06SGatien Chevallier 		case PTA_BSEC_FUSE_ACCESS:
73*4583de06SGatien Chevallier 			/* Check access */
74*4583de06SGatien Chevallier 			if (res)
75*4583de06SGatien Chevallier 				goto out;
76*4583de06SGatien Chevallier 			/* Read fuse value */
77*4583de06SGatien Chevallier 			res = stm32_bsec_shadow_read_otp(buf, otp_id);
78*4583de06SGatien Chevallier 			FMSG("Read fuse %"PRIu32" val: %#"PRIx32, otp_id, *buf);
79*4583de06SGatien Chevallier 			break;
80*4583de06SGatien Chevallier 		case PTA_BSEC_LOCKS_ACCESS:
81*4583de06SGatien Chevallier 			if (res) {
82*4583de06SGatien Chevallier 				/* Force error when access is not allowed */
83*4583de06SGatien Chevallier 				*buf = PTA_BSEC_LOCK_ERROR;
84*4583de06SGatien Chevallier 				continue;
85*4583de06SGatien Chevallier 			}
86*4583de06SGatien Chevallier 			*buf = 0;
87*4583de06SGatien Chevallier 			/* Read lock value */
88*4583de06SGatien Chevallier 			res = stm32_bsec_read_permanent_lock(otp_id, &locked);
89*4583de06SGatien Chevallier 			if (res)
90*4583de06SGatien Chevallier 				goto out;
91*4583de06SGatien Chevallier 
92*4583de06SGatien Chevallier 			if (locked)
93*4583de06SGatien Chevallier 				*buf |= PTA_BSEC_LOCK_PERM;
94*4583de06SGatien Chevallier 
95*4583de06SGatien Chevallier 			res = stm32_bsec_read_sr_lock(otp_id, &locked);
96*4583de06SGatien Chevallier 			if (res)
97*4583de06SGatien Chevallier 				goto out;
98*4583de06SGatien Chevallier 
99*4583de06SGatien Chevallier 			if (locked)
100*4583de06SGatien Chevallier 				*buf |= PTA_BSEC_LOCK_SHADOW_R;
101*4583de06SGatien Chevallier 
102*4583de06SGatien Chevallier 			res = stm32_bsec_read_sw_lock(otp_id, &locked);
103*4583de06SGatien Chevallier 			if (res)
104*4583de06SGatien Chevallier 				goto out;
105*4583de06SGatien Chevallier 
106*4583de06SGatien Chevallier 			if (locked)
107*4583de06SGatien Chevallier 				*buf |= PTA_BSEC_LOCK_SHADOW_W;
108*4583de06SGatien Chevallier 
109*4583de06SGatien Chevallier 			res = stm32_bsec_read_sp_lock(otp_id, &locked);
110*4583de06SGatien Chevallier 			if (res)
111*4583de06SGatien Chevallier 				goto out;
112*4583de06SGatien Chevallier 
113*4583de06SGatien Chevallier 			if (locked)
114*4583de06SGatien Chevallier 				*buf |= PTA_BSEC_LOCK_SHADOW_P;
115*4583de06SGatien Chevallier 
116*4583de06SGatien Chevallier 			FMSG("Read lock %"PRIu32" val: %#"PRIx32, otp_id, *buf);
117*4583de06SGatien Chevallier 			break;
118*4583de06SGatien Chevallier 		default:
119*4583de06SGatien Chevallier 			FMSG("%"PRIu32" invalid operation: %"PRIu32, otp_id,
120*4583de06SGatien Chevallier 			     bsec_command);
121*4583de06SGatien Chevallier 			res = TEE_ERROR_BAD_PARAMETERS;
122*4583de06SGatien Chevallier 		}
123*4583de06SGatien Chevallier 
124*4583de06SGatien Chevallier 		if (res)
125*4583de06SGatien Chevallier 			goto out;
126*4583de06SGatien Chevallier 	}
127*4583de06SGatien Chevallier 
128*4583de06SGatien Chevallier 	FMSG("Buffer orig %p, size %zu", buf, size);
129*4583de06SGatien Chevallier 
130*4583de06SGatien Chevallier 	res = TEE_SUCCESS;
131*4583de06SGatien Chevallier out:
132*4583de06SGatien Chevallier 	return res;
133*4583de06SGatien Chevallier }
134*4583de06SGatien Chevallier 
bsec_write_mem(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])135*4583de06SGatien Chevallier static TEE_Result bsec_write_mem(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS])
136*4583de06SGatien Chevallier {
137*4583de06SGatien Chevallier 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
138*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_MEMREF_INPUT,
139*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE,
140*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE);
141*4583de06SGatien Chevallier 
142*4583de06SGatien Chevallier 	uint32_t *buf = (uint32_t *)params[1].memref.buffer;
143*4583de06SGatien Chevallier 	size_t size = params[1].memref.size;
144*4583de06SGatien Chevallier 	uint32_t otp_start = 0;
145*4583de06SGatien Chevallier 	size_t otp_length = 0;
146*4583de06SGatien Chevallier 	uint32_t otp_id = 0;
147*4583de06SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
148*4583de06SGatien Chevallier 	unsigned int otp_base_offset = params[0].value.a;
149*4583de06SGatien Chevallier 	unsigned int bsec_command = params[0].value.b;
150*4583de06SGatien Chevallier 
151*4583de06SGatien Chevallier 	if (pt != exp_pt || !buf || !size ||
152*4583de06SGatien Chevallier 	    !IS_ALIGNED_WITH_TYPE(params[1].memref.buffer, uint32_t))
153*4583de06SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
154*4583de06SGatien Chevallier 
155*4583de06SGatien Chevallier 	/* Check 32bits alignment */
156*4583de06SGatien Chevallier 	if (otp_base_offset % BSEC_BYTES_PER_WORD ||
157*4583de06SGatien Chevallier 	    size % BSEC_BYTES_PER_WORD)
158*4583de06SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
159*4583de06SGatien Chevallier 
160*4583de06SGatien Chevallier 	otp_start = otp_base_offset / BSEC_BYTES_PER_WORD;
161*4583de06SGatien Chevallier 	otp_length = size / BSEC_BYTES_PER_WORD;
162*4583de06SGatien Chevallier 
163*4583de06SGatien Chevallier 	/* Initial check to ensure that all BSEC words are available */
164*4583de06SGatien Chevallier 	for (otp_id = otp_start; otp_id < otp_start + otp_length; otp_id++) {
165*4583de06SGatien Chevallier 		res = bsec_check_access(otp_id);
166*4583de06SGatien Chevallier 		if (res)
167*4583de06SGatien Chevallier 			return res;
168*4583de06SGatien Chevallier 	}
169*4583de06SGatien Chevallier 
170*4583de06SGatien Chevallier 	for (otp_id = otp_start; otp_id < otp_start + otp_length;
171*4583de06SGatien Chevallier 	     otp_id++, buf++) {
172*4583de06SGatien Chevallier 		switch (bsec_command) {
173*4583de06SGatien Chevallier 		case PTA_BSEC_SHADOW_ACCESS:
174*4583de06SGatien Chevallier 			/* Write shadow register */
175*4583de06SGatien Chevallier 			FMSG("Write shadow %"PRIx32" : %"PRIx32,
176*4583de06SGatien Chevallier 			     otp_id, *buf);
177*4583de06SGatien Chevallier 			res = stm32_bsec_write_otp(*buf, otp_id);
178*4583de06SGatien Chevallier 			break;
179*4583de06SGatien Chevallier 
180*4583de06SGatien Chevallier 		case PTA_BSEC_FUSE_ACCESS:
181*4583de06SGatien Chevallier 			/* Write fuse value */
182*4583de06SGatien Chevallier 			FMSG("Write fuse %"PRIx32" : %08"PRIx32,
183*4583de06SGatien Chevallier 			     otp_id, *buf);
184*4583de06SGatien Chevallier 			res = stm32_bsec_program_otp(*buf, otp_id);
185*4583de06SGatien Chevallier 			break;
186*4583de06SGatien Chevallier 
187*4583de06SGatien Chevallier 		case PTA_BSEC_LOCKS_ACCESS:
188*4583de06SGatien Chevallier 			if (*buf & PTA_BSEC_LOCK_PERM) {
189*4583de06SGatien Chevallier 				FMSG("Perm lock access OTP: %u", otp_id);
190*4583de06SGatien Chevallier 				res = stm32_bsec_permanent_lock_otp(otp_id);
191*4583de06SGatien Chevallier 				if (res)
192*4583de06SGatien Chevallier 					break;
193*4583de06SGatien Chevallier 			}
194*4583de06SGatien Chevallier 
195*4583de06SGatien Chevallier 			if (*buf & PTA_BSEC_LOCK_SHADOW_R) {
196*4583de06SGatien Chevallier 				FMSG("Shadow read lock");
197*4583de06SGatien Chevallier 				res = stm32_bsec_set_sr_lock(otp_id);
198*4583de06SGatien Chevallier 				if (res)
199*4583de06SGatien Chevallier 					break;
200*4583de06SGatien Chevallier 			}
201*4583de06SGatien Chevallier 
202*4583de06SGatien Chevallier 			if (*buf & PTA_BSEC_LOCK_SHADOW_W) {
203*4583de06SGatien Chevallier 				FMSG("Shadow write lock detected");
204*4583de06SGatien Chevallier 				res = stm32_bsec_set_sw_lock(otp_id);
205*4583de06SGatien Chevallier 				if (res)
206*4583de06SGatien Chevallier 					break;
207*4583de06SGatien Chevallier 			}
208*4583de06SGatien Chevallier 
209*4583de06SGatien Chevallier 			if (*buf & PTA_BSEC_LOCK_SHADOW_P) {
210*4583de06SGatien Chevallier 				FMSG("Shadow programming lock detected");
211*4583de06SGatien Chevallier 				res = stm32_bsec_set_sp_lock(otp_id);
212*4583de06SGatien Chevallier 			}
213*4583de06SGatien Chevallier 
214*4583de06SGatien Chevallier 			break;
215*4583de06SGatien Chevallier 
216*4583de06SGatien Chevallier 		default:
217*4583de06SGatien Chevallier 			FMSG("OTP %"PRIx32" invalid operation: %"PRIx32,
218*4583de06SGatien Chevallier 			     otp_id, bsec_command);
219*4583de06SGatien Chevallier 			res = TEE_ERROR_BAD_PARAMETERS;
220*4583de06SGatien Chevallier 		}
221*4583de06SGatien Chevallier 
222*4583de06SGatien Chevallier 		if (res)
223*4583de06SGatien Chevallier 			return res;
224*4583de06SGatien Chevallier 	}
225*4583de06SGatien Chevallier 
226*4583de06SGatien Chevallier 	return TEE_SUCCESS;
227*4583de06SGatien Chevallier }
228*4583de06SGatien Chevallier 
bsec_pta_state(uint32_t pt,TEE_Param params[TEE_NUM_PARAMS])229*4583de06SGatien Chevallier static TEE_Result bsec_pta_state(uint32_t pt, TEE_Param params[TEE_NUM_PARAMS])
230*4583de06SGatien Chevallier {
231*4583de06SGatien Chevallier 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
232*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE,
233*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE,
234*4583de06SGatien Chevallier 						TEE_PARAM_TYPE_NONE);
235*4583de06SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
236*4583de06SGatien Chevallier 	enum stm32_bsec_sec_state state = BSEC_STATE_INVALID;
237*4583de06SGatien Chevallier 	enum stm32_bsec_pta_sec_state pta_state = PTA_BSEC_STATE_INVALID;
238*4583de06SGatien Chevallier 
239*4583de06SGatien Chevallier 	if (pt != exp_pt)
240*4583de06SGatien Chevallier 		return TEE_ERROR_BAD_PARAMETERS;
241*4583de06SGatien Chevallier 
242*4583de06SGatien Chevallier 	res = stm32_bsec_get_state(&state);
243*4583de06SGatien Chevallier 	if (res)
244*4583de06SGatien Chevallier 		return res;
245*4583de06SGatien Chevallier 
246*4583de06SGatien Chevallier 	switch (state) {
247*4583de06SGatien Chevallier 	case BSEC_STATE_SEC_CLOSED:
248*4583de06SGatien Chevallier 		pta_state = PTA_BSEC_STATE_SEC_CLOSE;
249*4583de06SGatien Chevallier 		break;
250*4583de06SGatien Chevallier 	case BSEC_STATE_SEC_OPEN:
251*4583de06SGatien Chevallier 		pta_state = PTA_BSEC_STATE_SEC_OPEN;
252*4583de06SGatien Chevallier 		break;
253*4583de06SGatien Chevallier 	default:
254*4583de06SGatien Chevallier 		pta_state = PTA_BSEC_STATE_INVALID;
255*4583de06SGatien Chevallier 		break;
256*4583de06SGatien Chevallier 	}
257*4583de06SGatien Chevallier 
258*4583de06SGatien Chevallier 	params[0].value.a = pta_state;
259*4583de06SGatien Chevallier 
260*4583de06SGatien Chevallier 	return TEE_SUCCESS;
261*4583de06SGatien Chevallier }
262*4583de06SGatien Chevallier 
bsec_pta_invoke_command(void * pSessionContext __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])263*4583de06SGatien Chevallier static TEE_Result bsec_pta_invoke_command(void *pSessionContext __unused,
264*4583de06SGatien Chevallier 					  uint32_t cmd_id,
265*4583de06SGatien Chevallier 					  uint32_t param_types,
266*4583de06SGatien Chevallier 					  TEE_Param params[TEE_NUM_PARAMS])
267*4583de06SGatien Chevallier {
268*4583de06SGatien Chevallier 	FMSG(PTA_NAME" command %#"PRIx32" ptypes %#"PRIx32,
269*4583de06SGatien Chevallier 	     cmd_id, param_types);
270*4583de06SGatien Chevallier 
271*4583de06SGatien Chevallier 	switch (cmd_id) {
272*4583de06SGatien Chevallier 	case PTA_BSEC_CMD_READ_OTP:
273*4583de06SGatien Chevallier 		return bsec_read_mem(param_types, params);
274*4583de06SGatien Chevallier 	case PTA_BSEC_CMD_WRITE_OTP:
275*4583de06SGatien Chevallier 		return bsec_write_mem(param_types, params);
276*4583de06SGatien Chevallier 	case PTA_BSEC_CMD_GET_STATE:
277*4583de06SGatien Chevallier 		return bsec_pta_state(param_types, params);
278*4583de06SGatien Chevallier 	default:
279*4583de06SGatien Chevallier 		break;
280*4583de06SGatien Chevallier 	}
281*4583de06SGatien Chevallier 
282*4583de06SGatien Chevallier 	return TEE_ERROR_NOT_IMPLEMENTED;
283*4583de06SGatien Chevallier }
284*4583de06SGatien Chevallier 
pta_bsec_open_session(uint32_t ptypes __unused,TEE_Param par[TEE_NUM_PARAMS]__unused,void ** session __unused)285*4583de06SGatien Chevallier static TEE_Result pta_bsec_open_session(uint32_t ptypes __unused,
286*4583de06SGatien Chevallier 					TEE_Param par[TEE_NUM_PARAMS] __unused,
287*4583de06SGatien Chevallier 					void **session __unused)
288*4583de06SGatien Chevallier {
289*4583de06SGatien Chevallier 	uint32_t login = to_ta_session(ts_get_current_session())->clnt_id.login;
290*4583de06SGatien Chevallier 
291*4583de06SGatien Chevallier 	if (login == TEE_LOGIN_REE_KERNEL)
292*4583de06SGatien Chevallier 		return TEE_SUCCESS;
293*4583de06SGatien Chevallier 
294*4583de06SGatien Chevallier 	return TEE_ERROR_ACCESS_DENIED;
295*4583de06SGatien Chevallier }
296*4583de06SGatien Chevallier 
297*4583de06SGatien Chevallier pseudo_ta_register(.uuid = PTA_BSEC_UUID, .name = PTA_NAME,
298*4583de06SGatien Chevallier 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
299*4583de06SGatien Chevallier 			    TA_FLAG_DEVICE_ENUM,
300*4583de06SGatien Chevallier 		   .open_session_entry_point = pta_bsec_open_session,
301*4583de06SGatien Chevallier 		   .invoke_command_entry_point = bsec_pta_invoke_command);
302