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