Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Documentation/platforms/arm64/imx9/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,42 @@
NXP i.MX9
=========

Peripheral Support
==================

========== ======= =====================================================
Peripheral Support Notes
========== ======= =====================================================
ELE Yes EdgeLock Enclave, used for entropy and secure boot
RNG Yes ``/dev/random`` and ``/dev/urandom``, backed by the ELE
========== ======= =====================================================

RNG
---

The EdgeLock Enclave contains a true random number generator. ``CONFIG_IMX9_RNG``
registers it as ``/dev/random`` and ``/dev/urandom``, which is what seeds the
kernel entropy pool from hardware. Without it ``up_randompool_initialize()``
has no hardware source.

``CONFIG_IMX9_RNG`` selects ``CONFIG_IMX9_ELE`` and ``CONFIG_ARCH_HAVE_RNG``.
``CONFIG_DEV_RANDOM`` then defaults on; ``CONFIG_DEV_URANDOM`` does not and must
be set explicitly, after which ``CONFIG_DEV_URANDOM_ARCH`` selects the hardware
backend rather than the software PRNG.

A read is served in blocks, looping until the request is satisfied. Every block
is checked before it is returned, and a failed check is an error rather than a
short read: the buffer must have been written by the ELE, must not be all
zeros, and must differ from the previous block, which is the FIPS 140-2
continuous test.

.. code-block:: console

nsh> hexdump /dev/random -c 32
/dev/random at 00000000:
0000: 7c 9a f9 b0 fb 89 be 9d 23 bf 17 28 88 43 67 10
0010: c5 79 10 9e d7 be ca 42 2f 51 00 bd bc ce 77 54

Supported Boards
================

Expand Down
10 changes: 9 additions & 1 deletion arch/arm64/src/imx9/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,15 @@ if(CONFIG_IMX9_FLEXSPI_NOR)
endif()

if(CONFIG_IMX9_BOOTLOADER)
list(APPEND SRCS imx9_system_ctl.c imx9_trdc.c imx9_ele.c)
list(APPEND SRCS imx9_system_ctl.c imx9_trdc.c)
endif()

if(CONFIG_IMX9_ELE)
list(APPEND SRCS imx9_ele.c)
endif()

if(CONFIG_IMX9_RNG)
list(APPEND SRCS imx9_rng.c)
endif()

if(CONFIG_IMX9_ROMAPI)
Expand Down
15 changes: 15 additions & 0 deletions arch/arm64/src/imx9/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ config IMX9_BOOTLOADER
bool "Bootloader"
select ARM64_DECODEFIQ if ARCH_ARM64_EXCEPTION_LEVEL = 3
select IMX9_DDR_TRAINING if ARCH_ARM64_EXCEPTION_LEVEL = 3
select IMX9_ELE
Comment thread
xiaoxiang781216 marked this conversation as resolved.
default n
---help---
Configure NuttX as the bootloader. NuttX will be compiled
Expand Down Expand Up @@ -125,8 +126,22 @@ config IMX_AHAB_CNTR_ADDR
---help---
Physical address where the AHAB container header is loaded into memory.

config IMX9_ELE
bool
default n

menu "i.MX9 Peripheral Selection"

config IMX9_RNG
bool "ELE true random number generator"
default n
select IMX9_ELE
select ARCH_HAVE_RNG
---help---
Register /dev/random and /dev/urandom, both backed by the ELE
true random number generator. Without this the entropy pool is
never seeded from hardware.

config IMX9_EDMA
bool "eDMA"
default n
Expand Down
7 changes: 7 additions & 0 deletions arch/arm64/src/imx9/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,16 @@ endif
ifeq ($(CONFIG_IMX9_BOOTLOADER),y)
CHIP_CSRCS += imx9_system_ctl.c
CHIP_CSRCS += imx9_trdc.c
endif

ifeq ($(CONFIG_IMX9_ELE),y)
CHIP_CSRCS += imx9_ele.c
endif

ifeq ($(CONFIG_IMX9_RNG),y)
CHIP_CSRCS += imx9_rng.c
endif

ifeq ($(CONFIG_IMX9_ROMAPI),y)
CHIP_CSRCS += imx9_romapi.c
endif
Comment thread
xiaoxiang781216 marked this conversation as resolved.
Expand Down
84 changes: 73 additions & 11 deletions arch/arm64/src/imx9/imx9_ele.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* Included Files
****************************************************************************/

#include <nuttx/arch.h>
#include <nuttx/debug.h>
#include <errno.h>

Expand Down Expand Up @@ -146,6 +147,30 @@ static void imx9_ele_receivemsg(struct ele_msg *msg_ptr)
}
}

/****************************************************************************
* Name: imx9_ele_buffer_pa
*
* Description:
* Physical address of a buffer the ELE will read or write. The enclave
* addresses memory physically while cache maintenance takes the virtual
* address, so a caller holding one of them cannot supply the other.
*
* Returned Value:
* The physical address, or zero if the buffer is not mapped.
*
****************************************************************************/

static uintptr_t imx9_ele_buffer_pa(void *va)
{
#ifdef CONFIG_ARCH_USE_MMU
return up_addrenv_va_to_pa(va);
#else
/* Without translation the virtual address is the physical one. */

return (uintptr_t)va;
#endif
}

/****************************************************************************
* Public Functions
****************************************************************************/
Expand Down Expand Up @@ -199,6 +224,9 @@ uint32_t imx9_ele_read_common_fuse(uint32_t fuse_id)
int imx9_ele_get_key(uint8_t *key, size_t key_size,
uint8_t *ctx, size_t ctx_size)
{
uintptr_t key_pa;
uintptr_t ctx_pa;

if (!key)
{
_err("Invalid key parameter\n");
Expand Down Expand Up @@ -229,17 +257,27 @@ int imx9_ele_get_key(uint8_t *key, size_t key_size,
return -EINVAL;
}

key_pa = imx9_ele_buffer_pa(key);
ctx_pa = imx9_ele_buffer_pa(ctx);

if (key_pa == 0 || ctx_pa == 0)
{
_err("Buffer is not mapped\n");
return -EFAULT;
}

msg.header.version = ELE_VERSION;
msg.header.tag = ELE_CMD_TAG;
msg.header.size = 7;
msg.header.command = ELE_DERIVE_KEY_REQ;
msg.data[0] = upper_32_bits((ulong)key);
msg.data[1] = lower_32_bits((ulong)key);
msg.data[2] = upper_32_bits((ulong)ctx);
msg.data[3] = lower_32_bits((ulong)ctx);
msg.data[0] = upper_32_bits((ulong)key_pa);
msg.data[1] = lower_32_bits((ulong)key_pa);
msg.data[2] = upper_32_bits((ulong)ctx_pa);
msg.data[3] = lower_32_bits((ulong)ctx_pa);
msg.data[4] = ((ctx_size << 16) | key_size);

uint32_t crc = msg.header.data;

for (uint32_t i = 0; i < msg.header.size - 2; i++)
{
crc ^= msg.data[i];
Expand Down Expand Up @@ -424,6 +462,7 @@ int imx9_ele_get_trng_state(void)
{
struct ele_trng_state *ele_trng =
(struct ele_trng_state *)(msg.data + 1);

if (ele_trng->trng_state != ELE_TRNG_STATUS_READY ||
ele_trng->csal_state != ELE_CSAL_STATUS_READY)
{
Expand All @@ -442,17 +481,39 @@ int imx9_ele_get_trng_state(void)
return -EIO;
}

int imx9_ele_get_random(uint32_t paddr, size_t len)
int imx9_ele_get_random(void *buf, size_t len)
{
uint16_t counter = 0;
uint16_t max_tries = ELE_RNG_TIMEOUT_US / ELE_RNG_SLEEP_US;
uintptr_t paddr;

if (paddr == 0 || len == 0)
if (buf == NULL || len == 0)
{
_err("Wrong input parameters!\n");
return -EINVAL;
}

/* The buffer is invalidated after the transfer, so anything sharing its
* first or last cache line would lose whatever was written meanwhile.
*/

if (!IS_ALIGNED((uintptr_t)buf, ARMV8A_DCACHE_LINESIZE) ||
!IS_ALIGNED(len, ARMV8A_DCACHE_LINESIZE))
{
_err("Buffer is not a whole number of cache lines\n");
return -EINVAL;
}

paddr = imx9_ele_buffer_pa(buf);

/* The address travels in a single 32-bit message word. */

if (paddr == 0 || paddr > UINT32_MAX - len)
{
_err("Buffer is not mapped, or is beyond the ELE address range\n");
return -EFAULT;
}

while ((imx9_ele_get_trng_state() != 0))
{
if (counter > max_tries)
Expand All @@ -465,16 +526,18 @@ int imx9_ele_get_random(uint32_t paddr, size_t len)
counter++;
}

/* Flush the cache before sending the request to ELE. */
/* Cache maintenance takes the virtual address; the ELE takes the
* physical one.
*/

up_flush_dcache((uintptr_t)paddr, (uintptr_t)(paddr + len));
up_flush_dcache((uintptr_t)buf, (uintptr_t)buf + len);

msg.header.version = ELE_VERSION_FW;
msg.header.tag = ELE_CMD_TAG;
msg.header.size = 4;
msg.header.command = ELE_GET_RNG_REQ;
msg.data[0] = 0;
msg.data[1] = paddr;
msg.data[1] = (uint32_t)paddr;
msg.data[2] = len;

imx9_ele_sendmsg(&msg);
Expand All @@ -484,8 +547,7 @@ int imx9_ele_get_random(uint32_t paddr, size_t len)
{
/* Invalidate the cache so we can read the result from RAM. */

up_invalidate_dcache((uintptr_t)paddr,
(uintptr_t)(paddr + len));
up_invalidate_dcache((uintptr_t)buf, (uintptr_t)buf + len);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/src/imx9/imx9_ele.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ int imx9_ele_get_trng_state(void);
*
****************************************************************************/

int imx9_ele_get_random(uint32_t paddr, size_t len);
int imx9_ele_get_random(void *buf, size_t len);

/****************************************************************************
* Name: imx9_ele_commit
Expand Down
Loading
Loading