1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2025, Pengutronix, Michael Tretter <entwicklung@pengutronix.de>
4 */
5
6 #include <config.h>
7 #include <drivers/rockchip_otp.h>
8 #include <kernel/pseudo_ta.h>
9 #include <kernel/tee_misc.h>
10 #include <tee/uuid.h>
11 #include <utee_defines.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <platform_config.h>
15
16 #include <pta_rk_secure_boot.h>
17
18 #define PTA_NAME "rk_secure_boot.pta"
19
20 /*
21 * The hash is stored in OTP in little endian. The PTA assumes that OP-TEE is
22 * in little endian and may copy the hash from memory to OTP without ensuring
23 * the byte order.
24 */
25 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
26
test_bit_mask(uint32_t value,uint32_t mask)27 static inline bool test_bit_mask(uint32_t value, uint32_t mask)
28 {
29 return (value & mask) == mask;
30 }
31
32 #define HASH_STRING_SIZE 88
33 static_assert(ROCKCHIP_OTP_RSA_HASH_SIZE == 8);
otp_to_string(uint32_t * otp,char * str,size_t str_size)34 static __maybe_unused char *otp_to_string(uint32_t *otp,
35 char *str, size_t str_size)
36 {
37 snprintf(str, str_size,
38 "0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32
39 " 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32,
40 otp[0], otp[1], otp[2], otp[3],
41 otp[4], otp[5], otp[6], otp[7]);
42
43 return str;
44 }
45
write_key_size(uint32_t key_size_bits)46 static TEE_Result write_key_size(uint32_t key_size_bits)
47 {
48 uint32_t idx = ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX;
49 uint32_t sz = ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE;
50 TEE_Result res = TEE_SUCCESS;
51 uint32_t status = 0;
52
53 IMSG("Setting key size to %"PRId32, key_size_bits);
54
55 switch (key_size_bits) {
56 case 4096:
57 status |= ROCKCHIP_OTP_SECURE_BOOT_STATUS_RSA4096;
58
59 res = rockchip_otp_write_secure(&status, idx, sz);
60 if (res)
61 return res;
62
63 res = rockchip_otp_read_secure(&status, idx, sz);
64 if (res)
65 return res;
66 if (!test_bit_mask(status,
67 ROCKCHIP_OTP_SECURE_BOOT_STATUS_RSA4096))
68 return TEE_ERROR_GENERIC;
69 break;
70 case 2048:
71 /* Nothing to do */
72 break;
73 default:
74 res = TEE_ERROR_BAD_PARAMETERS;
75 break;
76 }
77
78 return res;
79 }
80
write_hash(uint32_t * hash,size_t size)81 static TEE_Result write_hash(uint32_t *hash, size_t size)
82 {
83 char __maybe_unused str[HASH_STRING_SIZE] = {};
84 uint32_t tmp[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
85 TEE_Result res = TEE_SUCCESS;
86
87 if (size != ROCKCHIP_OTP_RSA_HASH_SIZE)
88 return TEE_ERROR_GENERIC;
89
90 IMSG("Burning hash %s", otp_to_string(hash, str, sizeof(str)));
91
92 res = rockchip_otp_write_secure(hash,
93 ROCKCHIP_OTP_RSA_HASH_INDEX,
94 ROCKCHIP_OTP_RSA_HASH_SIZE);
95 if (res)
96 return res;
97
98 res = rockchip_otp_read_secure(tmp,
99 ROCKCHIP_OTP_RSA_HASH_INDEX,
100 ROCKCHIP_OTP_RSA_HASH_SIZE);
101 if (res)
102 return res;
103 if (memcmp(tmp, hash, sizeof(tmp))) {
104 EMSG("Failed to burn hash. OTP is %s",
105 otp_to_string(tmp, str, sizeof(str)));
106 return res;
107 }
108
109 return res;
110 }
111
get_info(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])112 static TEE_Result get_info(uint32_t param_types,
113 TEE_Param params[TEE_NUM_PARAMS])
114 {
115 uint32_t hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
116 char __maybe_unused str[HASH_STRING_SIZE] = {};
117 struct pta_rk_secure_boot_info *info = NULL;
118 TEE_Result res = TEE_ERROR_GENERIC;
119 uint32_t status = 0;
120
121 if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
122 TEE_PARAM_TYPE_NONE,
123 TEE_PARAM_TYPE_NONE,
124 TEE_PARAM_TYPE_NONE))
125 return TEE_ERROR_BAD_PARAMETERS;
126
127 if (!IS_ALIGNED_WITH_TYPE(params[0].memref.buffer, typeof(*info)))
128 return TEE_ERROR_BAD_PARAMETERS;
129
130 info = params[0].memref.buffer;
131 if (!info || params[0].memref.size != sizeof(*info))
132 return TEE_ERROR_BAD_PARAMETERS;
133
134 memset(info, 0, sizeof(*info));
135
136 res = rockchip_otp_read_secure(&status,
137 ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
138 ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
139 if (res)
140 return res;
141
142 res = rockchip_otp_read_secure(hash,
143 ROCKCHIP_OTP_RSA_HASH_INDEX,
144 ROCKCHIP_OTP_RSA_HASH_SIZE);
145 if (res)
146 return res;
147
148 DMSG("Current hash: %s", otp_to_string(hash, str, sizeof(str)));
149
150 info->enabled = test_bit_mask(status,
151 ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE);
152 info->simulation = IS_ENABLED(CFG_RK_SECURE_BOOT_SIMULATION);
153 memcpy(info->hash.value, hash, sizeof(info->hash.value));
154
155 return TEE_SUCCESS;
156 }
157
burn_hash(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])158 static TEE_Result burn_hash(uint32_t param_types,
159 TEE_Param params[TEE_NUM_PARAMS])
160 {
161 uint32_t new_hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
162 uint32_t old_hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
163 uint32_t zero[ROCKCHIP_OTP_RSA_HASH_SIZE] = { 0 };
164 char __maybe_unused str[HASH_STRING_SIZE] = {};
165 struct pta_rk_secure_boot_hash *hash = NULL;
166 TEE_Result res = TEE_SUCCESS;
167 uint32_t key_size_bits = 0;
168 uint32_t status = 0;
169 size_t hash_sz = 0;
170
171 if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
172 TEE_PARAM_TYPE_VALUE_INPUT,
173 TEE_PARAM_TYPE_NONE,
174 TEE_PARAM_TYPE_NONE))
175 return TEE_ERROR_BAD_PARAMETERS;
176
177 hash = params[0].memref.buffer;
178 hash_sz = params[0].memref.size;
179 if (!hash || hash_sz != sizeof(*hash))
180 return TEE_ERROR_BAD_PARAMETERS;
181 memcpy(new_hash, hash->value, sizeof(new_hash));
182
183 key_size_bits = params[1].value.a;
184 if (key_size_bits != 4096 && key_size_bits != 2048) {
185 EMSG("Invalid key size: %"PRId32, key_size_bits);
186 return TEE_ERROR_BAD_PARAMETERS;
187 }
188
189 res = rockchip_otp_read_secure(old_hash,
190 ROCKCHIP_OTP_RSA_HASH_INDEX,
191 ROCKCHIP_OTP_RSA_HASH_SIZE);
192 if (res)
193 return res;
194
195 /* If a hash is already set, ensure new hash matches the old hash. */
196 if (memcmp(old_hash, zero, sizeof(zero)) &&
197 memcmp(old_hash, new_hash, sizeof(new_hash))) {
198 EMSG("Refusing to burn hash %s",
199 otp_to_string(new_hash, str, sizeof(str)));
200 EMSG("OTP hash is %s",
201 otp_to_string(old_hash, str, sizeof(str)));
202 return TEE_ERROR_BAD_PARAMETERS;
203 }
204
205 /*
206 * Check if secure boot is already enabled after verifying the
207 * parameters for reporting the correct error if the command would
208 * result in the same state as the already fused board.
209 */
210 res = rockchip_otp_read_secure(&status,
211 ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
212 ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
213 if (res)
214 return res;
215 if (test_bit_mask(status, ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE)) {
216 DMSG("Secure boot already enabled");
217 return TEE_SUCCESS;
218 }
219
220 if (IS_ENABLED(CFG_RK_SECURE_BOOT_SIMULATION)) {
221 IMSG("Simulation mode: Skip burning hash %s, key size %"PRId32,
222 otp_to_string(new_hash, str, sizeof(str)), key_size_bits);
223 return TEE_SUCCESS;
224 }
225
226 res = write_hash(new_hash, ARRAY_SIZE(new_hash));
227 if (res) {
228 EMSG("Failed to write hash");
229 return res;
230 }
231
232 res = write_key_size(key_size_bits);
233 if (res) {
234 EMSG("Failed to write key size");
235 return res;
236 }
237
238 return TEE_SUCCESS;
239 }
240
lockdown_device(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS]__unused)241 static TEE_Result lockdown_device(uint32_t param_types,
242 TEE_Param params[TEE_NUM_PARAMS] __unused)
243 {
244 uint32_t hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
245 uint32_t zero[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
246 TEE_Result res = TEE_ERROR_GENERIC;
247 uint32_t status = 0;
248
249 if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
250 TEE_PARAM_TYPE_NONE,
251 TEE_PARAM_TYPE_NONE,
252 TEE_PARAM_TYPE_NONE))
253 return TEE_ERROR_BAD_PARAMETERS;
254
255 res = rockchip_otp_read_secure(hash,
256 ROCKCHIP_OTP_RSA_HASH_INDEX,
257 ROCKCHIP_OTP_RSA_HASH_SIZE);
258 if (res)
259 return res;
260 if (!memcmp(zero, hash, sizeof(hash))) {
261 EMSG("OTP hash is all zeros. Refuse lockdown.");
262 return TEE_ERROR_GENERIC;
263 }
264
265 res = rockchip_otp_read_secure(&status,
266 ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
267 ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
268 if (res)
269 return res;
270 if (test_bit_mask(status, ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE)) {
271 DMSG("Secure boot already enabled");
272 return TEE_SUCCESS;
273 }
274
275 status |= ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE;
276
277 if (IS_ENABLED(CFG_RK_SECURE_BOOT_SIMULATION)) {
278 IMSG("Simulation mode: Skip writing status: %"PRIx32,
279 status);
280 return TEE_SUCCESS;
281 }
282
283 IMSG("Writing secure boot status: %"PRIx32, status);
284 res = rockchip_otp_write_secure(&status,
285 ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
286 ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
287 if (res)
288 return res;
289
290 res = rockchip_otp_read_secure(&status,
291 ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
292 ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
293 if (res)
294 return res;
295 if (!test_bit_mask(status, ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE)) {
296 EMSG("Failed to write secure boot status");
297 return TEE_ERROR_GENERIC;
298 }
299
300 return TEE_SUCCESS;
301 }
302
invoke_command(void * sess_ctx __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])303 static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id,
304 uint32_t param_types,
305 TEE_Param params[TEE_NUM_PARAMS])
306 {
307 TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
308 TEE_Param bparams[TEE_NUM_PARAMS] = { };
309 TEE_Result res2 = TEE_ERROR_GENERIC;
310 TEE_Param *eparams = NULL;
311
312 res = to_bounce_params(param_types, params, bparams, &eparams);
313 if (res)
314 return res;
315
316 switch (cmd_id) {
317 case PTA_RK_SECURE_BOOT_GET_INFO:
318 res = get_info(param_types, eparams);
319 break;
320 case PTA_RK_SECURE_BOOT_BURN_HASH:
321 res = burn_hash(param_types, eparams);
322 break;
323 case PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE:
324 res = lockdown_device(param_types, eparams);
325 break;
326 default:
327 break;
328 }
329
330 res2 = from_bounce_params(param_types, params, bparams, eparams);
331 if (!res && res2)
332 res = res2;
333
334 return res;
335 }
336
337 pseudo_ta_register(.uuid = PTA_RK_SECURE_BOOT_UUID,
338 .name = PTA_NAME,
339 .flags = PTA_DEFAULT_FLAGS,
340 .invoke_command_entry_point = invoke_command);
341