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