xref: /optee_os/core/drivers/crypto/ele/ele.c (revision 79b6146ce215751c3f7baaeb11ac219ddab6fde5)
17114b0c5SSahil Malhotra // SPDX-License-Identifier: BSD-2-Clause
27114b0c5SSahil Malhotra /*
306f66bf9SSahil Malhotra  * Copyright 2022-2023, 2025 NXP
47114b0c5SSahil Malhotra  */
57114b0c5SSahil Malhotra #include <drivers/imx_mu.h>
606f66bf9SSahil Malhotra #include <ele.h>
77114b0c5SSahil Malhotra #include <initcall.h>
87114b0c5SSahil Malhotra #include <kernel/boot.h>
97114b0c5SSahil Malhotra #include <kernel/delay.h>
107114b0c5SSahil Malhotra #include <kernel/panic.h>
117114b0c5SSahil Malhotra #include <kernel/tee_common_otp.h>
1266810831SClement Faure #include <memutils.h>
137114b0c5SSahil Malhotra #include <mm/core_memprot.h>
147114b0c5SSahil Malhotra #include <mm/core_mmu.h>
1585a5d97eSSahil Malhotra #include <rng_support.h>
167114b0c5SSahil Malhotra #include <stdint.h>
1785a5d97eSSahil Malhotra #include <string_ext.h>
187114b0c5SSahil Malhotra #include <tee/cache.h>
197114b0c5SSahil Malhotra #include <tee_api_defines.h>
207114b0c5SSahil Malhotra #include <trace.h>
217114b0c5SSahil Malhotra #include <types_ext.h>
227114b0c5SSahil Malhotra #include <utee_types.h>
237114b0c5SSahil Malhotra #include <util.h>
247114b0c5SSahil Malhotra 
257114b0c5SSahil Malhotra #define ELE_BASE_ADDR MU_BASE
267114b0c5SSahil Malhotra #define ELE_BASE_SIZE MU_SIZE
277114b0c5SSahil Malhotra 
287114b0c5SSahil Malhotra #define ELE_VERSION_BASELINE 0x06
297114b0c5SSahil Malhotra #define ELE_COMMAND_SUCCEED 0xd6
3006f66bf9SSahil Malhotra #define ELE_COMMAND_FAILED  0x29
317114b0c5SSahil Malhotra #define ELE_RESPONSE_TAG    0xe1
327114b0c5SSahil Malhotra 
337114b0c5SSahil Malhotra #define ELE_CMD_SESSION_OPEN	    0x10
347114b0c5SSahil Malhotra #define ELE_CMD_SESSION_CLOSE	    0x11
357114b0c5SSahil Malhotra #define ELE_CMD_RNG_GET		    0xCD
367114b0c5SSahil Malhotra #define ELE_CMD_TRNG_STATE	    0xA4
377114b0c5SSahil Malhotra #define ELE_CMD_GET_INFO	    0xDA
387114b0c5SSahil Malhotra #define ELE_CMD_DERIVE_KEY	    0xA9
394734f2cfSSahil Malhotra #define ELE_CMD_SAB_INIT	    0x17
407114b0c5SSahil Malhotra 
417114b0c5SSahil Malhotra #define IMX_ELE_TRNG_STATUS_READY 0x3
427114b0c5SSahil Malhotra 
437114b0c5SSahil Malhotra #define ELE_MU_IRQ 0x0
447114b0c5SSahil Malhotra 
457114b0c5SSahil Malhotra #define CACHELINE_SIZE 64
467114b0c5SSahil Malhotra 
4706f66bf9SSahil Malhotra register_phys_mem_pgdir(MEM_AREA_IO_SEC, MU_BASE, MU_SIZE);
487114b0c5SSahil Malhotra 
4966810831SClement Faure struct get_info_rsp {
507114b0c5SSahil Malhotra 	uint32_t rsp_code;
517114b0c5SSahil Malhotra 	uint16_t soc_id;
527114b0c5SSahil Malhotra 	uint16_t soc_rev;
537114b0c5SSahil Malhotra 	uint16_t lifecycle;
5466810831SClement Faure 	uint8_t sssm_state;
5566810831SClement Faure 	uint8_t unused_1;
567114b0c5SSahil Malhotra 	uint32_t uid[4];
577114b0c5SSahil Malhotra 	uint32_t sha256_rom_patch[8];
5866810831SClement Faure 	uint32_t sha256_firmware[8];
5966810831SClement Faure 	uint32_t oem_srkh[16];
6066810831SClement Faure 	uint8_t trng_state;
6166810831SClement Faure 	uint8_t csal_state;
62*de9f0c25SSahil Malhotra #ifndef CFG_MX95
6366810831SClement Faure 	uint8_t imem_state;
6466810831SClement Faure 	uint8_t unused_2;
65*de9f0c25SSahil Malhotra #else
66*de9f0c25SSahil Malhotra 	uint8_t unused_2[2];
67*de9f0c25SSahil Malhotra 	uint32_t oem_pqc_srkh[16];
68*de9f0c25SSahil Malhotra 	uint32_t rsvd[8];
69*de9f0c25SSahil Malhotra #endif
707114b0c5SSahil Malhotra } __packed;
717114b0c5SSahil Malhotra 
727114b0c5SSahil Malhotra struct response_code {
737114b0c5SSahil Malhotra 	uint8_t status;
747114b0c5SSahil Malhotra 	uint8_t rating;
757114b0c5SSahil Malhotra 	uint16_t rating_extension;
767114b0c5SSahil Malhotra } __packed;
777114b0c5SSahil Malhotra 
787114b0c5SSahil Malhotra /*
797114b0c5SSahil Malhotra  * Print ELE response status and rating
807114b0c5SSahil Malhotra  *
817114b0c5SSahil Malhotra  * @rsp response code structure
827114b0c5SSahil Malhotra  */
print_rsp_code(struct response_code rsp __maybe_unused)837114b0c5SSahil Malhotra static void print_rsp_code(struct response_code rsp __maybe_unused)
847114b0c5SSahil Malhotra {
857114b0c5SSahil Malhotra 	DMSG("Response status %#"PRIx8", rating %#"PRIx8" (ext %#"PRIx16")",
867114b0c5SSahil Malhotra 	     rsp.status, rsp.rating, rsp.rating_extension);
877114b0c5SSahil Malhotra }
887114b0c5SSahil Malhotra 
897114b0c5SSahil Malhotra /*
907114b0c5SSahil Malhotra  * Print ELE message header
917114b0c5SSahil Malhotra  *
927114b0c5SSahil Malhotra  * @hdr message header
937114b0c5SSahil Malhotra  */
print_msg_header(struct imx_mu_msg_header hdr __maybe_unused)947114b0c5SSahil Malhotra static void print_msg_header(struct imx_mu_msg_header hdr __maybe_unused)
957114b0c5SSahil Malhotra {
967114b0c5SSahil Malhotra 	DMSG("Header ver %#"PRIx8", size %"PRId8", tag %#"PRIx8", cmd %#"PRIx8,
977114b0c5SSahil Malhotra 	     hdr.version, hdr.size, hdr.tag, hdr.command);
987114b0c5SSahil Malhotra }
997114b0c5SSahil Malhotra 
1007114b0c5SSahil Malhotra /*
1017114b0c5SSahil Malhotra  * Print full ELE message content
1027114b0c5SSahil Malhotra  *
1037114b0c5SSahil Malhotra  * @msg message
1047114b0c5SSahil Malhotra  */
dump_message(const struct imx_mu_msg * msg __maybe_unused)1057114b0c5SSahil Malhotra static void dump_message(const struct imx_mu_msg *msg __maybe_unused)
1067114b0c5SSahil Malhotra {
1077114b0c5SSahil Malhotra 	size_t i = 0;
1087114b0c5SSahil Malhotra 	size_t size __maybe_unused = msg->header.size;
1097114b0c5SSahil Malhotra 	uint32_t *data __maybe_unused = (uint32_t *)msg;
1107114b0c5SSahil Malhotra 
1117114b0c5SSahil Malhotra 	DMSG("Dump of message %p(%zu)", data, size);
1127114b0c5SSahil Malhotra 	for (i = 0; i < size; i++)
1137114b0c5SSahil Malhotra 		DMSG("word %zu: %#"PRIx32, i, data[i]);
1147114b0c5SSahil Malhotra }
1157114b0c5SSahil Malhotra 
1167114b0c5SSahil Malhotra /*
1177114b0c5SSahil Malhotra  * The CRC for the message is computed xor-ing all the words of the message:
1187114b0c5SSahil Malhotra  * the header and all the words except the word storing the CRC.
1197114b0c5SSahil Malhotra  *
1207114b0c5SSahil Malhotra  * @msg MU message to hash
1217114b0c5SSahil Malhotra  */
compute_crc(const struct imx_mu_msg * msg)1227114b0c5SSahil Malhotra static uint32_t compute_crc(const struct imx_mu_msg *msg)
1237114b0c5SSahil Malhotra {
1247114b0c5SSahil Malhotra 	uint32_t crc = 0;
1257114b0c5SSahil Malhotra 	uint8_t i = 0;
1267114b0c5SSahil Malhotra 	uint32_t *payload = (uint32_t *)msg;
1277114b0c5SSahil Malhotra 
1287114b0c5SSahil Malhotra 	assert(msg);
1297114b0c5SSahil Malhotra 
1307114b0c5SSahil Malhotra 	for (i = 0; i < msg->header.size - 1; i++)
1317114b0c5SSahil Malhotra 		crc ^= payload[i];
1327114b0c5SSahil Malhotra 
1337114b0c5SSahil Malhotra 	return crc;
1347114b0c5SSahil Malhotra }
1357114b0c5SSahil Malhotra 
update_crc(struct imx_mu_msg * msg)13606f66bf9SSahil Malhotra void update_crc(struct imx_mu_msg *msg)
1377114b0c5SSahil Malhotra {
1387114b0c5SSahil Malhotra 	assert(msg);
1397114b0c5SSahil Malhotra 	/*
1407114b0c5SSahil Malhotra 	 * The CRC field is the last element of array. The size of the header
1417114b0c5SSahil Malhotra 	 * is also subtracted from CRC computation.
1427114b0c5SSahil Malhotra 	 */
1437114b0c5SSahil Malhotra 	msg->data.u32[msg->header.size - 2] = compute_crc(msg);
1447114b0c5SSahil Malhotra }
1457114b0c5SSahil Malhotra 
1467114b0c5SSahil Malhotra /*
1477114b0c5SSahil Malhotra  * Return the given MU base address, depending on the MMU state.
1487114b0c5SSahil Malhotra  *
1497114b0c5SSahil Malhotra  * @pa MU physical base address
1507114b0c5SSahil Malhotra  * @sz MU size
1517114b0c5SSahil Malhotra  */
imx_ele_init(paddr_t pa,size_t sz)1527114b0c5SSahil Malhotra static vaddr_t imx_ele_init(paddr_t pa, size_t sz)
1537114b0c5SSahil Malhotra {
1547114b0c5SSahil Malhotra 	static bool is_initialized;
1557114b0c5SSahil Malhotra 	vaddr_t va = 0;
1567114b0c5SSahil Malhotra 
1577114b0c5SSahil Malhotra 	assert(pa && sz);
1587114b0c5SSahil Malhotra 
1597114b0c5SSahil Malhotra 	if (cpu_mmu_enabled())
1607114b0c5SSahil Malhotra 		va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz);
1617114b0c5SSahil Malhotra 	else
1627114b0c5SSahil Malhotra 		va = (vaddr_t)pa;
1637114b0c5SSahil Malhotra 
1647114b0c5SSahil Malhotra 	if (!is_initialized) {
1657114b0c5SSahil Malhotra 		imx_mu_init(va);
1667114b0c5SSahil Malhotra 		is_initialized = true;
1677114b0c5SSahil Malhotra 	}
1687114b0c5SSahil Malhotra 
1697114b0c5SSahil Malhotra 	return va;
1707114b0c5SSahil Malhotra }
1717114b0c5SSahil Malhotra 
1727114b0c5SSahil Malhotra /*
1737114b0c5SSahil Malhotra  * Extract response codes from the given word
1747114b0c5SSahil Malhotra  *
1757114b0c5SSahil Malhotra  * @word 32 bits word MU response
1767114b0c5SSahil Malhotra  */
get_response_code(uint32_t word)1777114b0c5SSahil Malhotra static struct response_code get_response_code(uint32_t word)
1787114b0c5SSahil Malhotra {
1797114b0c5SSahil Malhotra 	struct response_code rsp = {
1807114b0c5SSahil Malhotra 		.rating_extension = (word & GENMASK_32(31, 16)) >> 16,
1817114b0c5SSahil Malhotra 		.rating = (word & GENMASK_32(15, 8)) >> 8,
1827114b0c5SSahil Malhotra 		.status = (word & GENMASK_32(7, 0)) >> 0,
1837114b0c5SSahil Malhotra 	};
1847114b0c5SSahil Malhotra 
1857114b0c5SSahil Malhotra 	return rsp;
1867114b0c5SSahil Malhotra }
1877114b0c5SSahil Malhotra 
imx_ele_call(struct imx_mu_msg * msg)18806f66bf9SSahil Malhotra TEE_Result imx_ele_call(struct imx_mu_msg *msg)
1897114b0c5SSahil Malhotra {
1907114b0c5SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
1917114b0c5SSahil Malhotra 	struct response_code rsp = { };
1927114b0c5SSahil Malhotra 	vaddr_t va = 0;
1937114b0c5SSahil Malhotra 
1947114b0c5SSahil Malhotra 	assert(msg);
1957114b0c5SSahil Malhotra 
1967114b0c5SSahil Malhotra 	if (msg->header.tag != ELE_REQUEST_TAG) {
1977114b0c5SSahil Malhotra 		EMSG("Request has invalid tag: %#"PRIx8" instead of %#"PRIx8,
1987114b0c5SSahil Malhotra 		     msg->header.tag, ELE_REQUEST_TAG);
1997114b0c5SSahil Malhotra 		return TEE_ERROR_BAD_PARAMETERS;
2007114b0c5SSahil Malhotra 	}
2017114b0c5SSahil Malhotra 
2027114b0c5SSahil Malhotra 	va = imx_ele_init(ELE_BASE_ADDR, ELE_BASE_SIZE);
2037114b0c5SSahil Malhotra 	if (!va) {
2047114b0c5SSahil Malhotra 		EMSG("Fail to get base address");
2057114b0c5SSahil Malhotra 		return TEE_ERROR_GENERIC;
2067114b0c5SSahil Malhotra 	}
2077114b0c5SSahil Malhotra 
2087114b0c5SSahil Malhotra 	res = imx_mu_call(va, msg, true);
2097114b0c5SSahil Malhotra 	if (res) {
2107114b0c5SSahil Malhotra 		EMSG("Failed to transmit message: %#"PRIx32, res);
2117114b0c5SSahil Malhotra 		print_msg_header(msg->header);
2127114b0c5SSahil Malhotra 		dump_message(msg);
2137114b0c5SSahil Malhotra 		return res;
2147114b0c5SSahil Malhotra 	}
2157114b0c5SSahil Malhotra 
2167114b0c5SSahil Malhotra 	rsp = get_response_code(msg->data.u32[0]);
2177114b0c5SSahil Malhotra 
2187114b0c5SSahil Malhotra 	if (msg->header.tag != ELE_RESPONSE_TAG) {
2197114b0c5SSahil Malhotra 		EMSG("Response has invalid tag: %#"PRIx8" instead of %#"PRIx8,
2207114b0c5SSahil Malhotra 		     msg->header.tag, ELE_RESPONSE_TAG);
2217114b0c5SSahil Malhotra 		print_msg_header(msg->header);
2227114b0c5SSahil Malhotra 		return TEE_ERROR_GENERIC;
2237114b0c5SSahil Malhotra 	}
2247114b0c5SSahil Malhotra 
2257114b0c5SSahil Malhotra 	if (rsp.status != ELE_COMMAND_SUCCEED) {
2267114b0c5SSahil Malhotra 		EMSG("Command has failed");
2277114b0c5SSahil Malhotra 		print_rsp_code(rsp);
2287114b0c5SSahil Malhotra 		return TEE_ERROR_GENERIC;
2297114b0c5SSahil Malhotra 	}
2307114b0c5SSahil Malhotra 
2317114b0c5SSahil Malhotra 	/* The rating can be different in success and failing cases */
2327114b0c5SSahil Malhotra 	if (rsp.rating != 0) {
2337114b0c5SSahil Malhotra 		EMSG("Command has invalid rating: %#"PRIx8, rsp.rating);
2347114b0c5SSahil Malhotra 		print_rsp_code(rsp);
2357114b0c5SSahil Malhotra 		return TEE_ERROR_GENERIC;
2367114b0c5SSahil Malhotra 	}
2377114b0c5SSahil Malhotra 
2387114b0c5SSahil Malhotra 	return TEE_SUCCESS;
2397114b0c5SSahil Malhotra }
2407114b0c5SSahil Malhotra 
2417114b0c5SSahil Malhotra /*
2427114b0c5SSahil Malhotra  * Open a session with EdgeLock Enclave. It returns a session handle.
2437114b0c5SSahil Malhotra  *
2447114b0c5SSahil Malhotra  * @session_handle EdgeLock Enclave session handle
2457114b0c5SSahil Malhotra  */
imx_ele_session_open(uint32_t * session_handle)24666810831SClement Faure static TEE_Result __maybe_unused imx_ele_session_open(uint32_t *session_handle)
2477114b0c5SSahil Malhotra {
2487114b0c5SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
2497114b0c5SSahil Malhotra 	struct open_session_cmd {
250f680c915SSahil Malhotra 		uint8_t rsvd1;
2517114b0c5SSahil Malhotra 		uint8_t interrupt_num;
252f680c915SSahil Malhotra 		uint16_t rsvd2;
2537114b0c5SSahil Malhotra 		uint8_t priority;
2547114b0c5SSahil Malhotra 		uint8_t op_mode;
255f680c915SSahil Malhotra 		uint16_t rsvd3;
2567114b0c5SSahil Malhotra 	} __packed cmd = {
257f680c915SSahil Malhotra 		.rsvd1 = 0,
2587114b0c5SSahil Malhotra 		.interrupt_num = ELE_MU_IRQ,
259f680c915SSahil Malhotra 		.rsvd2 = 0,
2607114b0c5SSahil Malhotra 		.priority = 0,
2617114b0c5SSahil Malhotra 		.op_mode = 0,
262f680c915SSahil Malhotra 		.rsvd3 = 0,
2637114b0c5SSahil Malhotra 	};
2647114b0c5SSahil Malhotra 	struct open_session_rsp {
2657114b0c5SSahil Malhotra 		uint32_t rsp_code;
2667114b0c5SSahil Malhotra 		uint32_t session_handle;
2677114b0c5SSahil Malhotra 	} rsp = { };
2687114b0c5SSahil Malhotra 	struct imx_mu_msg msg = {
2697114b0c5SSahil Malhotra 		.header.version = ELE_VERSION_HSM,
2707114b0c5SSahil Malhotra 		.header.size = SIZE_MSG_32(cmd),
2717114b0c5SSahil Malhotra 		.header.tag = ELE_REQUEST_TAG,
2727114b0c5SSahil Malhotra 		.header.command = ELE_CMD_SESSION_OPEN,
2737114b0c5SSahil Malhotra 	};
2747114b0c5SSahil Malhotra 
2757114b0c5SSahil Malhotra 	assert(session_handle);
2767114b0c5SSahil Malhotra 
2777114b0c5SSahil Malhotra 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
2787114b0c5SSahil Malhotra 
2797114b0c5SSahil Malhotra 	res = imx_ele_call(&msg);
2807114b0c5SSahil Malhotra 	if (res)
2817114b0c5SSahil Malhotra 		return res;
2827114b0c5SSahil Malhotra 
2837114b0c5SSahil Malhotra 	memcpy(&rsp, msg.data.u8, sizeof(rsp));
2847114b0c5SSahil Malhotra 
2857114b0c5SSahil Malhotra 	*session_handle = rsp.session_handle;
2867114b0c5SSahil Malhotra 
2877114b0c5SSahil Malhotra 	return TEE_SUCCESS;
2887114b0c5SSahil Malhotra }
2897114b0c5SSahil Malhotra 
2907114b0c5SSahil Malhotra /*
2917114b0c5SSahil Malhotra  * Close a session with EdgeLock Enclave.
2927114b0c5SSahil Malhotra  *
2937114b0c5SSahil Malhotra  * @session_handle EdgeLock Enclave session handle
2947114b0c5SSahil Malhotra  */
imx_ele_session_close(uint32_t session_handle)29566810831SClement Faure static TEE_Result __maybe_unused imx_ele_session_close(uint32_t session_handle)
2967114b0c5SSahil Malhotra {
2977114b0c5SSahil Malhotra 	struct close_session_cmd {
2987114b0c5SSahil Malhotra 		uint32_t session_handle;
2997114b0c5SSahil Malhotra 	} cmd = {
3007114b0c5SSahil Malhotra 		.session_handle = session_handle,
3017114b0c5SSahil Malhotra 	};
3027114b0c5SSahil Malhotra 	struct imx_mu_msg msg = {
3037114b0c5SSahil Malhotra 		.header.version = ELE_VERSION_HSM,
3047114b0c5SSahil Malhotra 		.header.size = SIZE_MSG_32(cmd),
3057114b0c5SSahil Malhotra 		.header.tag = ELE_REQUEST_TAG,
3067114b0c5SSahil Malhotra 		.header.command = ELE_CMD_SESSION_CLOSE,
3077114b0c5SSahil Malhotra 	};
3087114b0c5SSahil Malhotra 
3097114b0c5SSahil Malhotra 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
3107114b0c5SSahil Malhotra 
3117114b0c5SSahil Malhotra 	return imx_ele_call(&msg);
3127114b0c5SSahil Malhotra }
3137114b0c5SSahil Malhotra 
imx_ele_get_device_info(struct get_info_rsp * rsp)31466810831SClement Faure static TEE_Result imx_ele_get_device_info(struct get_info_rsp *rsp)
3157114b0c5SSahil Malhotra {
31666810831SClement Faure 	TEE_Result res = TEE_ERROR_GENERIC;
31766810831SClement Faure 	struct imx_ele_buf output = { };
31866810831SClement Faure 	struct {
31966810831SClement Faure 		uint32_t addr_msb;
32066810831SClement Faure 		uint32_t addr_lsb;
32166810831SClement Faure 		uint16_t size;
32266810831SClement Faure 	} __packed cmd = { };
32366810831SClement Faure 	struct imx_mu_msg msg = {
32466810831SClement Faure 		.header.version = ELE_VERSION_BASELINE,
32566810831SClement Faure 		.header.size = SIZE_MSG_32(cmd),
32666810831SClement Faure 		.header.tag = ELE_REQUEST_TAG,
32766810831SClement Faure 		.header.command = ELE_CMD_GET_INFO,
32866810831SClement Faure 	};
3297114b0c5SSahil Malhotra 
33066810831SClement Faure 	if (!rsp)
33166810831SClement Faure 		return TEE_ERROR_BAD_PARAMETERS;
33266810831SClement Faure 
33366810831SClement Faure 	res = imx_ele_buf_alloc(&output, NULL, sizeof(*rsp));
33466810831SClement Faure 	if (res)
3357114b0c5SSahil Malhotra 		goto out;
3367114b0c5SSahil Malhotra 
33766810831SClement Faure 	cmd.addr_msb = output.paddr_msb;
33866810831SClement Faure 	cmd.addr_lsb = output.paddr_lsb;
33966810831SClement Faure 	cmd.size = sizeof(*rsp);
3407114b0c5SSahil Malhotra 
34166810831SClement Faure 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
3427114b0c5SSahil Malhotra 
34366810831SClement Faure 	res = imx_ele_call(&msg);
34466810831SClement Faure 	if (res)
34566810831SClement Faure 		goto out;
3467114b0c5SSahil Malhotra 
34766810831SClement Faure 	res = imx_ele_buf_copy(&output, (uint8_t *)rsp, sizeof(*rsp));
3487114b0c5SSahil Malhotra out:
34966810831SClement Faure 	imx_ele_buf_free(&output);
35066810831SClement Faure 
35166810831SClement Faure 	return res;
35266810831SClement Faure }
35366810831SClement Faure 
tee_otp_get_die_id(uint8_t * buffer,size_t len)35466810831SClement Faure int tee_otp_get_die_id(uint8_t *buffer, size_t len)
35566810831SClement Faure {
35666810831SClement Faure 	static uint32_t uid[4];
35766810831SClement Faure 	static bool is_fetched;
35866810831SClement Faure 	struct get_info_rsp rsp = { };
35966810831SClement Faure 
36066810831SClement Faure 	assert(buffer && len);
36166810831SClement Faure 
36266810831SClement Faure 	if (!is_fetched) {
36366810831SClement Faure 		if (imx_ele_get_device_info(&rsp))
36466810831SClement Faure 			panic("Fail to get the device UID");
36566810831SClement Faure 
36666810831SClement Faure 		memcpy(uid, rsp.uid, MIN(sizeof(rsp.uid), len));
36766810831SClement Faure 		is_fetched = true;
36866810831SClement Faure 	}
36966810831SClement Faure 
37066810831SClement Faure 	memcpy(buffer, uid, MIN(sizeof(uid), len));
3717114b0c5SSahil Malhotra 
3727114b0c5SSahil Malhotra 	return 0;
3737114b0c5SSahil Malhotra }
3747114b0c5SSahil Malhotra 
3753d8c192aSSahil Malhotra #if defined(CFG_MX93) || defined(CFG_MX91) || defined(CFG_MX95)
imx_ele_derive_key(const uint8_t * ctx,size_t ctx_size,uint8_t * key,size_t key_size)376bc7d76b6SClement Faure static TEE_Result imx_ele_derive_key(const uint8_t *ctx, size_t ctx_size,
377bc7d76b6SClement Faure 				     uint8_t *key, size_t key_size)
3787114b0c5SSahil Malhotra {
3797114b0c5SSahil Malhotra 	TEE_Result res = TEE_ERROR_GENERIC;
3807114b0c5SSahil Malhotra 	struct key_derive_cmd {
3817114b0c5SSahil Malhotra 		uint32_t key_addr_msb;
3827114b0c5SSahil Malhotra 		uint32_t key_addr_lsb;
3837114b0c5SSahil Malhotra 		uint32_t ctx_addr_msb;
3847114b0c5SSahil Malhotra 		uint32_t ctx_addr_lsb;
3857114b0c5SSahil Malhotra 		uint16_t key_size;
3867114b0c5SSahil Malhotra 		uint16_t ctx_size;
3877114b0c5SSahil Malhotra 		uint32_t crc;
3887114b0c5SSahil Malhotra 	} __packed cmd = { };
3897114b0c5SSahil Malhotra 	struct imx_mu_msg msg = {
3907114b0c5SSahil Malhotra 		.header.version = ELE_VERSION_BASELINE,
3917114b0c5SSahil Malhotra 		.header.size = SIZE_MSG_32(cmd),
3927114b0c5SSahil Malhotra 		.header.tag = ELE_REQUEST_TAG,
3937114b0c5SSahil Malhotra 		.header.command = ELE_CMD_DERIVE_KEY,
3947114b0c5SSahil Malhotra 	};
395bc7d76b6SClement Faure 	struct imx_ele_buf ele_ctx = { };
396bc7d76b6SClement Faure 	struct imx_ele_buf ele_key = { };
3977114b0c5SSahil Malhotra 
398bc7d76b6SClement Faure 	assert(ctx && key);
399bc7d76b6SClement Faure 
400bc7d76b6SClement Faure 	if (key_size != 16 && key_size != 32)
401bc7d76b6SClement Faure 		return TEE_ERROR_BAD_PARAMETERS;
402bc7d76b6SClement Faure 
403bc7d76b6SClement Faure 	res = imx_ele_buf_alloc(&ele_ctx, ctx, ctx_size);
404bc7d76b6SClement Faure 	if (res)
4057114b0c5SSahil Malhotra 		goto out;
4067114b0c5SSahil Malhotra 
407bc7d76b6SClement Faure 	res = imx_ele_buf_alloc(&ele_key, key, key_size);
408bc7d76b6SClement Faure 	if (res)
409bc7d76b6SClement Faure 		goto out;
4107114b0c5SSahil Malhotra 
411bc7d76b6SClement Faure 	cmd.key_addr_lsb = ele_key.paddr_lsb;
412bc7d76b6SClement Faure 	cmd.key_addr_msb = ele_key.paddr_msb;
413bc7d76b6SClement Faure 	cmd.key_size = key_size;
4147114b0c5SSahil Malhotra 
415bc7d76b6SClement Faure 	cmd.ctx_addr_lsb = ele_ctx.paddr_lsb;
416bc7d76b6SClement Faure 	cmd.ctx_addr_msb = ele_ctx.paddr_msb;
417bc7d76b6SClement Faure 	cmd.ctx_size = ctx_size;
4187114b0c5SSahil Malhotra 
4197114b0c5SSahil Malhotra 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
4207114b0c5SSahil Malhotra 	update_crc(&msg);
4217114b0c5SSahil Malhotra 
4227114b0c5SSahil Malhotra 	res = imx_ele_call(&msg);
4237114b0c5SSahil Malhotra 	if (res)
424bc7d76b6SClement Faure 		goto out;
4257114b0c5SSahil Malhotra 
426bc7d76b6SClement Faure 	res = imx_ele_buf_copy(&ele_key, key, key_size);
427bc7d76b6SClement Faure out:
428bc7d76b6SClement Faure 	imx_ele_buf_free(&ele_key);
429bc7d76b6SClement Faure 	imx_ele_buf_free(&ele_ctx);
430bc7d76b6SClement Faure 
431bc7d76b6SClement Faure 	return res;
432bc7d76b6SClement Faure }
433bc7d76b6SClement Faure 
tee_otp_get_hw_unique_key(struct tee_hw_unique_key * hwkey)434bc7d76b6SClement Faure TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
435bc7d76b6SClement Faure {
436bc7d76b6SClement Faure 	static const char pattern[] = "TEE_for_HUK_ELE";
437bc7d76b6SClement Faure 	static uint8_t key[HW_UNIQUE_KEY_LENGTH];
438bc7d76b6SClement Faure 	static bool is_fetched;
439bc7d76b6SClement Faure 
440bc7d76b6SClement Faure 	if (is_fetched)
441bc7d76b6SClement Faure 		goto out;
442bc7d76b6SClement Faure 
443bc7d76b6SClement Faure 	if (imx_ele_derive_key((const uint8_t *)pattern, sizeof(pattern), key,
444bc7d76b6SClement Faure 			       sizeof(key)))
445bc7d76b6SClement Faure 		panic("Fail to get HUK from ELE");
446bc7d76b6SClement Faure 
4477114b0c5SSahil Malhotra 	is_fetched = true;
4487114b0c5SSahil Malhotra out:
4497114b0c5SSahil Malhotra 	memcpy(hwkey->data, key,
4507114b0c5SSahil Malhotra 	       MIN(sizeof(key), (size_t)HW_UNIQUE_KEY_LENGTH));
4517114b0c5SSahil Malhotra 
4527114b0c5SSahil Malhotra 	return TEE_SUCCESS;
4537114b0c5SSahil Malhotra }
454b161b5e4SClement Faure 
455b161b5e4SClement Faure /*
456b161b5e4SClement Faure  * Get the current state of the ELE TRNG
457b161b5e4SClement Faure  */
imx_ele_rng_get_trng_state(void)458b161b5e4SClement Faure static TEE_Result imx_ele_rng_get_trng_state(void)
459b161b5e4SClement Faure {
460b161b5e4SClement Faure 	TEE_Result res = TEE_ERROR_GENERIC;
461b161b5e4SClement Faure 	struct rng_get_trng_state_msg_rsp {
462b161b5e4SClement Faure 		uint32_t rsp_code;
463b161b5e4SClement Faure 		uint8_t trng_state;
464b161b5e4SClement Faure 		uint8_t csal_state;
465b161b5e4SClement Faure 	} __packed rsp = { };
466b161b5e4SClement Faure 	struct imx_mu_msg msg = {
467b161b5e4SClement Faure 		.header.version = ELE_VERSION_BASELINE,
468b161b5e4SClement Faure 		.header.size = 1,
469b161b5e4SClement Faure 		.header.tag = ELE_REQUEST_TAG,
470b161b5e4SClement Faure 		.header.command = ELE_CMD_TRNG_STATE,
471b161b5e4SClement Faure 	};
472b161b5e4SClement Faure 
473b161b5e4SClement Faure 	res = imx_ele_call(&msg);
474b161b5e4SClement Faure 	if (res)
475b161b5e4SClement Faure 		return res;
476b161b5e4SClement Faure 
477b161b5e4SClement Faure 	memcpy(&rsp, msg.data.u8, sizeof(rsp));
478b161b5e4SClement Faure 
479b161b5e4SClement Faure 	if (rsp.trng_state != IMX_ELE_TRNG_STATUS_READY)
480b161b5e4SClement Faure 		return TEE_ERROR_BUSY;
481b161b5e4SClement Faure 	else
482b161b5e4SClement Faure 		return TEE_SUCCESS;
483b161b5e4SClement Faure }
484b161b5e4SClement Faure 
48585a5d97eSSahil Malhotra /*
48685a5d97eSSahil Malhotra  * Get random data from the EdgeLock Enclave.
48785a5d97eSSahil Malhotra  *
48885a5d97eSSahil Malhotra  * This function can be called when the MMU is off or on.
48985a5d97eSSahil Malhotra  * virtual/physical address translation and cache maintenance
49085a5d97eSSahil Malhotra  * is performed if needed.
49185a5d97eSSahil Malhotra  *
49285a5d97eSSahil Malhotra  * @buffer: data output
49385a5d97eSSahil Malhotra  * @size: RNG data size
49485a5d97eSSahil Malhotra  */
imx_ele_rng_get_random(uint8_t * buffer,size_t size)49585a5d97eSSahil Malhotra static TEE_Result imx_ele_rng_get_random(uint8_t *buffer, size_t size)
496b161b5e4SClement Faure {
497b161b5e4SClement Faure 	TEE_Result res = TEE_ERROR_GENERIC;
49885a5d97eSSahil Malhotra 	struct imx_ele_buf rng = { };
499b161b5e4SClement Faure 	struct rng_get_random_cmd {
500b161b5e4SClement Faure 		uint32_t addr_msb;
501b161b5e4SClement Faure 		uint32_t addr_lsb;
502b161b5e4SClement Faure 		uint32_t size;
503b161b5e4SClement Faure 	} cmd = { };
504b161b5e4SClement Faure 	struct imx_mu_msg msg = {
505b161b5e4SClement Faure 		.header.version = ELE_VERSION_HSM,
506b161b5e4SClement Faure 		.header.size = SIZE_MSG_32(cmd),
507b161b5e4SClement Faure 		.header.tag = ELE_REQUEST_TAG,
508b161b5e4SClement Faure 		.header.command = ELE_CMD_RNG_GET,
509b161b5e4SClement Faure 	};
510b161b5e4SClement Faure 
51185a5d97eSSahil Malhotra 	if (!buffer || !size)
51285a5d97eSSahil Malhotra 		return TEE_ERROR_BAD_PARAMETERS;
513b161b5e4SClement Faure 
51485a5d97eSSahil Malhotra 	if (cpu_mmu_enabled()) {
51585a5d97eSSahil Malhotra 		res = imx_ele_buf_alloc(&rng, NULL, size);
51685a5d97eSSahil Malhotra 		if (res != TEE_SUCCESS)
51785a5d97eSSahil Malhotra 			return res;
51885a5d97eSSahil Malhotra 
51985a5d97eSSahil Malhotra 		cmd.addr_msb = rng.paddr_msb;
52085a5d97eSSahil Malhotra 		cmd.addr_lsb = rng.paddr_lsb;
52185a5d97eSSahil Malhotra 	} else {
52285a5d97eSSahil Malhotra 		paddr_t pa = (paddr_t)buffer;
52385a5d97eSSahil Malhotra 
52485a5d97eSSahil Malhotra 		if (!IS_ALIGNED_WITH_TYPE(pa, uint32_t))
52585a5d97eSSahil Malhotra 			return TEE_ERROR_BAD_PARAMETERS;
52685a5d97eSSahil Malhotra 
52785a5d97eSSahil Malhotra 		reg_pair_from_64((uint64_t)pa, &cmd.addr_msb, &cmd.addr_lsb);
52885a5d97eSSahil Malhotra 	}
52985a5d97eSSahil Malhotra 
53085a5d97eSSahil Malhotra 	cmd.size = (uint32_t)size;
53185a5d97eSSahil Malhotra 
53285a5d97eSSahil Malhotra 	memcpy(msg.data.u8, &cmd, sizeof(cmd));
53385a5d97eSSahil Malhotra 
53485a5d97eSSahil Malhotra 	res = imx_ele_call(&msg);
53585a5d97eSSahil Malhotra 	if (res)
53685a5d97eSSahil Malhotra 		goto out;
53785a5d97eSSahil Malhotra 
53885a5d97eSSahil Malhotra 	if (cpu_mmu_enabled())
53985a5d97eSSahil Malhotra 		res = imx_ele_buf_copy(&rng, buffer, size);
54085a5d97eSSahil Malhotra out:
54185a5d97eSSahil Malhotra 	imx_ele_buf_free(&rng);
54285a5d97eSSahil Malhotra 
54385a5d97eSSahil Malhotra 	return res;
54485a5d97eSSahil Malhotra }
54585a5d97eSSahil Malhotra 
plat_get_aslr_seed(void)54685a5d97eSSahil Malhotra unsigned long plat_get_aslr_seed(void)
54785a5d97eSSahil Malhotra {
54885a5d97eSSahil Malhotra 	uint64_t timeout = timeout_init_us(10 * 1000);
54985a5d97eSSahil Malhotra 	unsigned long __aligned(CACHELINE_SIZE) aslr = 0;
550b161b5e4SClement Faure 
551b161b5e4SClement Faure 	/*
552b161b5e4SClement Faure 	 * Check the current TRNG state of the ELE. The TRNG must be
553b161b5e4SClement Faure 	 * started with a command earlier in the boot to allow the TRNG
554b161b5e4SClement Faure 	 * to generate enough entropy.
555b161b5e4SClement Faure 	 */
556b161b5e4SClement Faure 	while (imx_ele_rng_get_trng_state() == TEE_ERROR_BUSY)
557b161b5e4SClement Faure 		if (timeout_elapsed(timeout))
558b161b5e4SClement Faure 			panic("ELE RNG is busy");
559b161b5e4SClement Faure 
56085a5d97eSSahil Malhotra 	if (imx_ele_rng_get_random((uint8_t *)&aslr, sizeof(aslr)))
561b161b5e4SClement Faure 		panic("Cannot retrieve random data from ELE");
562b161b5e4SClement Faure 
563b161b5e4SClement Faure 	return aslr;
564b161b5e4SClement Faure }
56585a5d97eSSahil Malhotra 
56685a5d97eSSahil Malhotra #ifndef CFG_WITH_SOFTWARE_PRNG
hw_get_random_bytes(void * buf,size_t len)56785a5d97eSSahil Malhotra TEE_Result hw_get_random_bytes(void *buf, size_t len)
56885a5d97eSSahil Malhotra {
56985a5d97eSSahil Malhotra 	return imx_ele_rng_get_random((uint8_t *)buf, len);
57085a5d97eSSahil Malhotra }
57185a5d97eSSahil Malhotra #endif /* CFG_WITH_SOFTWARE_PRNG */
5727114b0c5SSahil Malhotra #endif /* CFG_MX93 || CFG_MX91 */
573