Add hw TRNG from SEL0 SP
Intgrates the FVP TRNG into the crypto sp to provide a hw
entropy source. Includes tests that check SP device
region configuration loading and MMIO access within the
region.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ia9af8b044596e1c7d194f039fdf64c2468bb3221
diff --git a/platform/drivers/arm/juno_trng/driver.cmake b/platform/drivers/arm/juno_trng/driver.cmake
new file mode 100644
index 0000000..6d51009
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/driver.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Add source files for using juno_trng and adapting it to the platform
+# trng interface.
+target_sources(${TGT} PRIVATE
+ "${CMAKE_CURRENT_LIST_DIR}/juno_trng.c"
+ "${CMAKE_CURRENT_LIST_DIR}/juno_trng_adapter.c"
+)
diff --git a/platform/drivers/arm/juno_trng/juno_decl.h b/platform/drivers/arm/juno_trng/juno_decl.h
new file mode 100644
index 0000000..07f2e19
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_decl.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This is a modified version of the juno trng platform driver from trusted-firmware-a.
+ * The code has been modified to allow the peripheral to be accessed by S-EL0 at
+ * an arbitrary virtual address.
+ */
+
+#ifndef JUNO_DECL_H
+#define JUNO_DECL_H
+
+#include <stdint.h>
+
+void juno_trng_set_base_addr(uintptr_t addr);
+int juno_getentropy(void *buf, size_t len);
+
+#endif /* JUNO_DECL_H */
diff --git a/platform/drivers/arm/juno_trng/juno_def.h b/platform/drivers/arm/juno_trng/juno_def.h
new file mode 100644
index 0000000..97d1e3c
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_def.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ *
+ * Based on the the trustedfirmware-a file with the same name. All but the
+ * TRNG defines are stripped out.
+ */
+
+#ifndef JUNO_DEF_H
+#define JUNO_DEF_H
+
+/*******************************************************************************
+ * TRNG related constants
+ ******************************************************************************/
+#define TRNG_NOUTPUTS 4
+#define TRNG_STATUS UL(0x10)
+#define TRNG_INTMASK UL(0x14)
+#define TRNG_CONFIG UL(0x18)
+#define TRNG_CONTROL UL(0x1C)
+#define TRNG_NBYTES 16 /* Number of bytes generated per round. */
+
+
+
+#endif /* JUNO_DEF_H */
diff --git a/platform/drivers/arm/juno_trng/juno_trng.c b/platform/drivers/arm/juno_trng/juno_trng.c
new file mode 100644
index 0000000..b520dba
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_trng.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * This is a modified version of the juno trng platform driver from trusted-firmware-a.
+ * The code has been modified to allow the peripheral to be accessed by S-EL0 at
+ * an arbitrary virtual address.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <util.h>
+#include "mmio.h"
+#include "juno_def.h"
+#include "juno_decl.h"
+
+/* The TRNG base address */
+static uintptr_t trng_base = 0;
+
+#define TRNG_BASE trng_base
+#define NSAMPLE_CLOCKS 1 /* min 1 cycle, max 231 cycles */
+#define NRETRIES 5
+
+/*
+ * Sets the base address used to access the peripheral. For
+ * S-EL0 operation, this will be a virtual address.
+ */
+void juno_trng_set_base_addr(uintptr_t addr)
+{
+ trng_base = addr;
+}
+
+static inline int output_valid(void)
+{
+ int i;
+
+ for (i = 0; i < NRETRIES; i++) {
+ uint32_t val;
+
+ val = mmio_read_32(TRNG_BASE + TRNG_STATUS);
+ if (val & 1U)
+ break;
+ }
+ if (i >= NRETRIES)
+ return 0; /* No output data available. */
+ return 1;
+}
+
+/*
+ * This function fills `buf` with `len` bytes of entropy.
+ * It uses the Trusted Entropy Source peripheral on Juno.
+ * Returns 0 when the buffer has been filled with entropy
+ * successfully and -1 otherwise.
+ */
+int juno_getentropy(void *buf, size_t len)
+{
+ uint8_t *bp = buf;
+
+ assert(buf);
+ assert(len);
+
+ /* Check for a valid base address */
+ if (!TRNG_BASE) return -1;
+
+ /* Disable interrupt mode. */
+ mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0);
+ /* Program TRNG to sample for `NSAMPLE_CLOCKS`. */
+ mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS);
+
+ while (len > 0) {
+ int i;
+
+ /* Start TRNG. */
+ mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1);
+
+ /* Check if output is valid. */
+ if (!output_valid())
+ return -1;
+
+ /* Fill entropy buffer. */
+ for (i = 0; i < TRNG_NOUTPUTS; i++) {
+ size_t n;
+ uint32_t val;
+
+ val = mmio_read_32(TRNG_BASE + i * sizeof(uint32_t));
+ n = MIN(len, sizeof(uint32_t));
+ memcpy(bp, &val, n);
+ bp += n;
+ len -= n;
+ if (len == 0)
+ break;
+ }
+
+ /* Reset TRNG outputs. */
+ mmio_write_32(TRNG_BASE + TRNG_STATUS, 1);
+ }
+
+ return 0;
+}
diff --git a/platform/drivers/arm/juno_trng/juno_trng_adapter.c b/platform/drivers/arm/juno_trng/juno_trng_adapter.c
new file mode 100644
index 0000000..3ad8b04
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/juno_trng_adapter.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <platform/interface/trng.h>
+#include <platform/interface/device_region.h>
+#include "juno_decl.h"
+
+/*
+ * A platform trng driver that uses the juno_trng driver from TF-A to provide a
+ * hardware entropy source.
+ */
+
+static int trng_poll(void *context, unsigned char *output, size_t nbyte, size_t *len)
+{
+ int status = 0;
+
+ *len = 0;
+
+ if (nbyte >= sizeof(unsigned char)) {
+
+ status = juno_getentropy(output, nbyte);
+
+ if (status == 0) {
+ *len = nbyte;
+ }
+ else {
+ /* Mbedtls currently crashes when a failure status is returned.
+ * This workaround prevents the crash for cases where no
+ * configuration has been provided for the trng.
+ */
+ status = 0;
+ *len = sizeof(unsigned char);
+ }
+ }
+
+ return status;
+}
+
+int platform_trng_create(struct platform_trng_driver *driver,
+ const struct device_region *device_region)
+{
+ static const struct platform_trng_iface iface = { .poll = trng_poll };
+
+ /*
+ * Default to leaving the driver in a safe but inoperable state.
+ */
+ driver->iface = &iface;
+ driver->context = NULL;
+
+ if (device_region) {
+
+ /*
+ * A device region has been provided, possibly from an external configuation.
+ */
+ juno_trng_set_base_addr(device_region->base_addr);
+ }
+
+ return 0;
+}
+
+void platform_trng_destroy(struct platform_trng_driver *driver)
+{
+ (void)driver;
+ juno_trng_set_base_addr(0);
+}
diff --git a/platform/drivers/arm/juno_trng/mmio.h b/platform/drivers/arm/juno_trng/mmio.h
new file mode 100644
index 0000000..da8d82f
--- /dev/null
+++ b/platform/drivers/arm/juno_trng/mmio.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copied from trustedfirmware-a and stripped down to only provide functions
+ * used by juno_trng.c.
+ */
+
+#ifndef MMIO_H
+#define MMIO_H
+
+#include <stdint.h>
+
+
+static inline void mmio_write_32(uintptr_t addr, uint32_t value)
+{
+ *(volatile uint32_t*)addr = value;
+}
+
+static inline uint32_t mmio_read_32(uintptr_t addr)
+{
+ return *(volatile uint32_t*)addr;
+}
+
+#endif /* MMIO_H */
diff --git a/platform/drivers/arm/tztrng/driver.cmake b/platform/drivers/arm/tztrng/driver.cmake
index 58d98c8..6a7f936 100644
--- a/platform/drivers/arm/tztrng/driver.cmake
+++ b/platform/drivers/arm/tztrng/driver.cmake
@@ -65,4 +65,4 @@
add_dependencies(${TGT} libcc_tztrng)
# Add adapter to map platform trng interface to tz-trng driver
-target_sources(${TGT} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/tztrng_trng.c")
+target_sources(${TGT} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/tztrng_adapter.c")
diff --git a/platform/drivers/arm/tztrng/tztrng_trng.c b/platform/drivers/arm/tztrng/tztrng_adapter.c
similarity index 100%
rename from platform/drivers/arm/tztrng/tztrng_trng.c
rename to platform/drivers/arm/tztrng/tztrng_adapter.c
diff --git a/platform/interface/device_region.h b/platform/interface/device_region.h
index 1ad1721..8bbf203 100644
--- a/platform/interface/device_region.h
+++ b/platform/interface/device_region.h
@@ -23,7 +23,7 @@
{
char dev_class[16]; /**< Identifier for class of device e.g. 'trng' */
int dev_instance; /**< Instance of the class of device on a platform */
- uint8_t *base_addr; /**< Base address or region */
+ uintptr_t base_addr; /**< Base address or region */
size_t io_region_size; /**< Size of I/O region in bytes */
};
diff --git a/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake b/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
index cb01389..ff7c049 100644
--- a/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
+++ b/platform/providers/arm/fvp/fvp_base_revc-2xaemv8a/platform.cmake
@@ -18,5 +18,5 @@
#
#-------------------------------------------------------------------------------
if ("trng" IN_LIST _platform_driver_dependencies)
- include(${TS_ROOT}/platform/drivers/arm/tztrng/driver.cmake)
+ include(${TS_ROOT}/platform/drivers/arm/juno_trng/driver.cmake)
endif()