xref: /optee_os/core/drivers/crypto/ele/ele.c (revision 35e561d87c7e50ccdbb8048ffa10a7f2b14756fb)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2022-2023, 2025 NXP
4  */
5 #include <drivers/imx_mu.h>
6 #include <ele.h>
7 #include <initcall.h>
8 #include <kernel/boot.h>
9 #include <kernel/delay.h>
10 #include <kernel/panic.h>
11 #include <kernel/tee_common_otp.h>
12 #include <memutils.h>
13 #include <mm/core_memprot.h>
14 #include <mm/core_mmu.h>
15 #include <stdint.h>
16 #include <tee/cache.h>
17 #include <tee_api_defines.h>
18 #include <trace.h>
19 #include <types_ext.h>
20 #include <utee_types.h>
21 #include <util.h>
22 
23 #define ELE_BASE_ADDR MU_BASE
24 #define ELE_BASE_SIZE MU_SIZE
25 
26 #define ELE_VERSION_BASELINE 0x06
27 #define ELE_COMMAND_SUCCEED 0xd6
28 #define ELE_COMMAND_FAILED  0x29
29 #define ELE_RESPONSE_TAG    0xe1
30 
31 #define ELE_CMD_SESSION_OPEN	    0x10
32 #define ELE_CMD_SESSION_CLOSE	    0x11
33 #define ELE_CMD_RNG_GET		    0xCD
34 #define ELE_CMD_TRNG_STATE	    0xA4
35 #define ELE_CMD_GET_INFO	    0xDA
36 #define ELE_CMD_DERIVE_KEY	    0xA9
37 #define ELE_CMD_SAB_INIT	    0x17
38 
39 #define IMX_ELE_TRNG_STATUS_READY 0x3
40 
41 #define ELE_MU_IRQ 0x0
42 
43 #define CACHELINE_SIZE 64
44 
45 register_phys_mem_pgdir(MEM_AREA_IO_SEC, MU_BASE, MU_SIZE);
46 
47 struct get_info_rsp {
48 	uint32_t rsp_code;
49 	uint16_t soc_id;
50 	uint16_t soc_rev;
51 	uint16_t lifecycle;
52 	uint8_t sssm_state;
53 	uint8_t unused_1;
54 	uint32_t uid[4];
55 	uint32_t sha256_rom_patch[8];
56 	uint32_t sha256_firmware[8];
57 	uint32_t oem_srkh[16];
58 	uint8_t trng_state;
59 	uint8_t csal_state;
60 	uint8_t imem_state;
61 	uint8_t unused_2;
62 } __packed;
63 
64 struct response_code {
65 	uint8_t status;
66 	uint8_t rating;
67 	uint16_t rating_extension;
68 } __packed;
69 
70 /*
71  * Print ELE response status and rating
72  *
73  * @rsp response code structure
74  */
75 static void print_rsp_code(struct response_code rsp __maybe_unused)
76 {
77 	DMSG("Response status %#"PRIx8", rating %#"PRIx8" (ext %#"PRIx16")",
78 	     rsp.status, rsp.rating, rsp.rating_extension);
79 }
80 
81 /*
82  * Print ELE message header
83  *
84  * @hdr message header
85  */
86 static void print_msg_header(struct imx_mu_msg_header hdr __maybe_unused)
87 {
88 	DMSG("Header ver %#"PRIx8", size %"PRId8", tag %#"PRIx8", cmd %#"PRIx8,
89 	     hdr.version, hdr.size, hdr.tag, hdr.command);
90 }
91 
92 /*
93  * Print full ELE message content
94  *
95  * @msg message
96  */
97 static void dump_message(const struct imx_mu_msg *msg __maybe_unused)
98 {
99 	size_t i = 0;
100 	size_t size __maybe_unused = msg->header.size;
101 	uint32_t *data __maybe_unused = (uint32_t *)msg;
102 
103 	DMSG("Dump of message %p(%zu)", data, size);
104 	for (i = 0; i < size; i++)
105 		DMSG("word %zu: %#"PRIx32, i, data[i]);
106 }
107 
108 /*
109  * The CRC for the message is computed xor-ing all the words of the message:
110  * the header and all the words except the word storing the CRC.
111  *
112  * @msg MU message to hash
113  */
114 static uint32_t compute_crc(const struct imx_mu_msg *msg)
115 {
116 	uint32_t crc = 0;
117 	uint8_t i = 0;
118 	uint32_t *payload = (uint32_t *)msg;
119 
120 	assert(msg);
121 
122 	for (i = 0; i < msg->header.size - 1; i++)
123 		crc ^= payload[i];
124 
125 	return crc;
126 }
127 
128 void update_crc(struct imx_mu_msg *msg)
129 {
130 	assert(msg);
131 	/*
132 	 * The CRC field is the last element of array. The size of the header
133 	 * is also subtracted from CRC computation.
134 	 */
135 	msg->data.u32[msg->header.size - 2] = compute_crc(msg);
136 }
137 
138 /*
139  * Return the given MU base address, depending on the MMU state.
140  *
141  * @pa MU physical base address
142  * @sz MU size
143  */
144 static vaddr_t imx_ele_init(paddr_t pa, size_t sz)
145 {
146 	static bool is_initialized;
147 	vaddr_t va = 0;
148 
149 	assert(pa && sz);
150 
151 	if (cpu_mmu_enabled())
152 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
153 	else
154 		va = (vaddr_t)pa;
155 
156 	if (!is_initialized) {
157 		imx_mu_init(va);
158 		is_initialized = true;
159 	}
160 
161 	return va;
162 }
163 
164 /*
165  * Extract response codes from the given word
166  *
167  * @word 32 bits word MU response
168  */
169 static struct response_code get_response_code(uint32_t word)
170 {
171 	struct response_code rsp = {
172 		.rating_extension = (word & GENMASK_32(31, 16)) >> 16,
173 		.rating = (word & GENMASK_32(15, 8)) >> 8,
174 		.status = (word & GENMASK_32(7, 0)) >> 0,
175 	};
176 
177 	return rsp;
178 }
179 
180 TEE_Result imx_ele_call(struct imx_mu_msg *msg)
181 {
182 	TEE_Result res = TEE_ERROR_GENERIC;
183 	struct response_code rsp = { };
184 	vaddr_t va = 0;
185 
186 	assert(msg);
187 
188 	if (msg->header.tag != ELE_REQUEST_TAG) {
189 		EMSG("Request has invalid tag: %#"PRIx8" instead of %#"PRIx8,
190 		     msg->header.tag, ELE_REQUEST_TAG);
191 		return TEE_ERROR_BAD_PARAMETERS;
192 	}
193 
194 	va = imx_ele_init(ELE_BASE_ADDR, ELE_BASE_SIZE);
195 	if (!va) {
196 		EMSG("Fail to get base address");
197 		return TEE_ERROR_GENERIC;
198 	}
199 
200 	res = imx_mu_call(va, msg, true);
201 	if (res) {
202 		EMSG("Failed to transmit message: %#"PRIx32, res);
203 		print_msg_header(msg->header);
204 		dump_message(msg);
205 		return res;
206 	}
207 
208 	rsp = get_response_code(msg->data.u32[0]);
209 
210 	if (msg->header.tag != ELE_RESPONSE_TAG) {
211 		EMSG("Response has invalid tag: %#"PRIx8" instead of %#"PRIx8,
212 		     msg->header.tag, ELE_RESPONSE_TAG);
213 		print_msg_header(msg->header);
214 		return TEE_ERROR_GENERIC;
215 	}
216 
217 	if (rsp.status != ELE_COMMAND_SUCCEED) {
218 		EMSG("Command has failed");
219 		print_rsp_code(rsp);
220 		return TEE_ERROR_GENERIC;
221 	}
222 
223 	/* The rating can be different in success and failing cases */
224 	if (rsp.rating != 0) {
225 		EMSG("Command has invalid rating: %#"PRIx8, rsp.rating);
226 		print_rsp_code(rsp);
227 		return TEE_ERROR_GENERIC;
228 	}
229 
230 	return TEE_SUCCESS;
231 }
232 
233 /*
234  * Open a session with EdgeLock Enclave. It returns a session handle.
235  *
236  * @session_handle EdgeLock Enclave session handle
237  */
238 static TEE_Result __maybe_unused imx_ele_session_open(uint32_t *session_handle)
239 {
240 	TEE_Result res = TEE_ERROR_GENERIC;
241 	struct open_session_cmd {
242 		uint8_t rsvd1;
243 		uint8_t interrupt_num;
244 		uint16_t rsvd2;
245 		uint8_t priority;
246 		uint8_t op_mode;
247 		uint16_t rsvd3;
248 	} __packed cmd = {
249 		.rsvd1 = 0,
250 		.interrupt_num = ELE_MU_IRQ,
251 		.rsvd2 = 0,
252 		.priority = 0,
253 		.op_mode = 0,
254 		.rsvd3 = 0,
255 	};
256 	struct open_session_rsp {
257 		uint32_t rsp_code;
258 		uint32_t session_handle;
259 	} rsp = { };
260 	struct imx_mu_msg msg = {
261 		.header.version = ELE_VERSION_HSM,
262 		.header.size = SIZE_MSG_32(cmd),
263 		.header.tag = ELE_REQUEST_TAG,
264 		.header.command = ELE_CMD_SESSION_OPEN,
265 	};
266 
267 	assert(session_handle);
268 
269 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
270 
271 	res = imx_ele_call(&msg);
272 	if (res)
273 		return res;
274 
275 	memcpy(&rsp, msg.data.u8, sizeof(rsp));
276 
277 	*session_handle = rsp.session_handle;
278 
279 	return TEE_SUCCESS;
280 }
281 
282 /*
283  * Close a session with EdgeLock Enclave.
284  *
285  * @session_handle EdgeLock Enclave session handle
286  */
287 static TEE_Result __maybe_unused imx_ele_session_close(uint32_t session_handle)
288 {
289 	struct close_session_cmd {
290 		uint32_t session_handle;
291 	} cmd = {
292 		.session_handle = session_handle,
293 	};
294 	struct imx_mu_msg msg = {
295 		.header.version = ELE_VERSION_HSM,
296 		.header.size = SIZE_MSG_32(cmd),
297 		.header.tag = ELE_REQUEST_TAG,
298 		.header.command = ELE_CMD_SESSION_CLOSE,
299 	};
300 
301 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
302 
303 	return imx_ele_call(&msg);
304 }
305 
306 static TEE_Result imx_ele_get_device_info(struct get_info_rsp *rsp)
307 {
308 	TEE_Result res = TEE_ERROR_GENERIC;
309 	struct imx_ele_buf output = { };
310 	struct {
311 		uint32_t addr_msb;
312 		uint32_t addr_lsb;
313 		uint16_t size;
314 	} __packed cmd = { };
315 	struct imx_mu_msg msg = {
316 		.header.version = ELE_VERSION_BASELINE,
317 		.header.size = SIZE_MSG_32(cmd),
318 		.header.tag = ELE_REQUEST_TAG,
319 		.header.command = ELE_CMD_GET_INFO,
320 	};
321 
322 	if (!rsp)
323 		return TEE_ERROR_BAD_PARAMETERS;
324 
325 	res = imx_ele_buf_alloc(&output, NULL, sizeof(*rsp));
326 	if (res)
327 		goto out;
328 
329 	cmd.addr_msb = output.paddr_msb;
330 	cmd.addr_lsb = output.paddr_lsb;
331 	cmd.size = sizeof(*rsp);
332 
333 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
334 
335 	res = imx_ele_call(&msg);
336 	if (res)
337 		goto out;
338 
339 	res = imx_ele_buf_copy(&output, (uint8_t *)rsp, sizeof(*rsp));
340 out:
341 	imx_ele_buf_free(&output);
342 
343 	return res;
344 }
345 
346 int tee_otp_get_die_id(uint8_t *buffer, size_t len)
347 {
348 	static uint32_t uid[4];
349 	static bool is_fetched;
350 	struct get_info_rsp rsp = { };
351 
352 	assert(buffer && len);
353 
354 	if (!is_fetched) {
355 		if (imx_ele_get_device_info(&rsp))
356 			panic("Fail to get the device UID");
357 
358 		memcpy(uid, rsp.uid, MIN(sizeof(rsp.uid), len));
359 		is_fetched = true;
360 	}
361 
362 	memcpy(buffer, uid, MIN(sizeof(uid), len));
363 
364 	return 0;
365 }
366 
367 /*
368  * Initialize EdgeLock Enclave services
369  */
370 static TEE_Result imx_ele_sab_init(void)
371 {
372 	struct imx_mu_msg msg = {
373 		.header.version = ELE_VERSION_HSM,
374 		.header.size = 1,
375 		.header.tag = ELE_REQUEST_TAG,
376 		.header.command = ELE_CMD_SAB_INIT,
377 	};
378 
379 	return imx_ele_call(&msg);
380 }
381 
382 driver_init(imx_ele_sab_init);
383 
384 #if defined(CFG_MX93) || defined(CFG_MX91)
385 static TEE_Result imx_ele_derive_key(const uint8_t *ctx, size_t ctx_size,
386 				     uint8_t *key, size_t key_size)
387 {
388 	TEE_Result res = TEE_ERROR_GENERIC;
389 	struct key_derive_cmd {
390 		uint32_t key_addr_msb;
391 		uint32_t key_addr_lsb;
392 		uint32_t ctx_addr_msb;
393 		uint32_t ctx_addr_lsb;
394 		uint16_t key_size;
395 		uint16_t ctx_size;
396 		uint32_t crc;
397 	} __packed cmd = { };
398 	struct imx_mu_msg msg = {
399 		.header.version = ELE_VERSION_BASELINE,
400 		.header.size = SIZE_MSG_32(cmd),
401 		.header.tag = ELE_REQUEST_TAG,
402 		.header.command = ELE_CMD_DERIVE_KEY,
403 	};
404 	struct imx_ele_buf ele_ctx = { };
405 	struct imx_ele_buf ele_key = { };
406 
407 	assert(ctx && key);
408 
409 	if (key_size != 16 && key_size != 32)
410 		return TEE_ERROR_BAD_PARAMETERS;
411 
412 	res = imx_ele_buf_alloc(&ele_ctx, ctx, ctx_size);
413 	if (res)
414 		goto out;
415 
416 	res = imx_ele_buf_alloc(&ele_key, key, key_size);
417 	if (res)
418 		goto out;
419 
420 	cmd.key_addr_lsb = ele_key.paddr_lsb;
421 	cmd.key_addr_msb = ele_key.paddr_msb;
422 	cmd.key_size = key_size;
423 
424 	cmd.ctx_addr_lsb = ele_ctx.paddr_lsb;
425 	cmd.ctx_addr_msb = ele_ctx.paddr_msb;
426 	cmd.ctx_size = ctx_size;
427 
428 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
429 	update_crc(&msg);
430 
431 	res = imx_ele_call(&msg);
432 	if (res)
433 		goto out;
434 
435 	res = imx_ele_buf_copy(&ele_key, key, key_size);
436 out:
437 	imx_ele_buf_free(&ele_key);
438 	imx_ele_buf_free(&ele_ctx);
439 
440 	return res;
441 }
442 
443 TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
444 {
445 	static const char pattern[] = "TEE_for_HUK_ELE";
446 	static uint8_t key[HW_UNIQUE_KEY_LENGTH];
447 	static bool is_fetched;
448 
449 	if (is_fetched)
450 		goto out;
451 
452 	if (imx_ele_derive_key((const uint8_t *)pattern, sizeof(pattern), key,
453 			       sizeof(key)))
454 		panic("Fail to get HUK from ELE");
455 
456 	is_fetched = true;
457 out:
458 	memcpy(hwkey->data, key,
459 	       MIN(sizeof(key), (size_t)HW_UNIQUE_KEY_LENGTH));
460 
461 	return TEE_SUCCESS;
462 }
463 
464 /*
465  * Get the current state of the ELE TRNG
466  */
467 static TEE_Result imx_ele_rng_get_trng_state(void)
468 {
469 	TEE_Result res = TEE_ERROR_GENERIC;
470 	struct rng_get_trng_state_msg_rsp {
471 		uint32_t rsp_code;
472 		uint8_t trng_state;
473 		uint8_t csal_state;
474 	} __packed rsp = { };
475 	struct imx_mu_msg msg = {
476 		.header.version = ELE_VERSION_BASELINE,
477 		.header.size = 1,
478 		.header.tag = ELE_REQUEST_TAG,
479 		.header.command = ELE_CMD_TRNG_STATE,
480 	};
481 
482 	res = imx_ele_call(&msg);
483 	if (res)
484 		return res;
485 
486 	memcpy(&rsp, msg.data.u8, sizeof(rsp));
487 
488 	if (rsp.trng_state != IMX_ELE_TRNG_STATUS_READY)
489 		return TEE_ERROR_BUSY;
490 	else
491 		return TEE_SUCCESS;
492 }
493 
494 unsigned long plat_get_aslr_seed(void)
495 {
496 	TEE_Result res = TEE_ERROR_GENERIC;
497 	uint64_t timeout = timeout_init_us(10 * 1000);
498 	struct rng_get_random_cmd {
499 		uint32_t addr_msb;
500 		uint32_t addr_lsb;
501 		uint32_t size;
502 		uint32_t crc;
503 	} cmd = { };
504 	struct imx_mu_msg msg = {
505 		.header.version = ELE_VERSION_HSM,
506 		.header.size = SIZE_MSG_32(cmd),
507 		.header.tag = ELE_REQUEST_TAG,
508 		.header.command = ELE_CMD_RNG_GET,
509 	};
510 	unsigned long aslr __aligned(CACHELINE_SIZE) = 0;
511 
512 	/*
513 	 * This function can only be called when the MMU is off. No
514 	 * virtual/physical address translation is performed, nor cache
515 	 * maintenance.
516 	 */
517 	assert(!cpu_mmu_enabled());
518 
519 	reg_pair_from_64((uint64_t)&aslr, &cmd.addr_msb, &cmd.addr_lsb);
520 	cmd.size = sizeof(aslr);
521 
522 	/*
523 	 * Check the current TRNG state of the ELE. The TRNG must be
524 	 * started with a command earlier in the boot to allow the TRNG
525 	 * to generate enough entropy.
526 	 */
527 	while (imx_ele_rng_get_trng_state() == TEE_ERROR_BUSY)
528 		if (timeout_elapsed(timeout))
529 			panic("ELE RNG is busy");
530 
531 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
532 	update_crc(&msg);
533 
534 	res = imx_ele_call(&msg);
535 	if (res)
536 		panic("Cannot retrieve random data from ELE");
537 
538 	return aslr;
539 }
540 #endif /* CFG_MX93 || CFG_MX91 */
541