crypto/fsl: add RNG support
authorMichael Walle <michael@walle.cc>
Sat, 27 Jun 2020 20:58:53 +0000 (22:58 +0200)
committerPriyanka Jain <priyanka.jain@nxp.com>
Mon, 27 Jul 2020 08:46:29 +0000 (14:16 +0530)
Register the random number generator with the rng subsystem in u-boot.
This way it can be used by EFI as well as for the 'rng' command.

Signed-off-by: Michael Walle <michael@walle.cc>
Tested-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
drivers/crypto/fsl/Kconfig
drivers/crypto/fsl/Makefile
drivers/crypto/fsl/jobdesc.c
drivers/crypto/fsl/jobdesc.h
drivers/crypto/fsl/jr.c
drivers/crypto/fsl/rng.c [new file with mode: 0644]

index 181a1e5..5ed6140 100644 (file)
@@ -45,3 +45,17 @@ config SYS_FSL_SEC_COMPAT
 
 config SYS_FSL_SEC_LE
        bool "Little-endian access to Freescale Secure Boot"
+
+if FSL_CAAM
+
+config FSL_CAAM_RNG
+       bool "Enable Random Number Generator support"
+       depends on DM_RNG
+       default y
+       help
+         Enable support for the hardware based random number generator
+         module of the CAAM. The random data is fetched from the DRGB
+         using the prediction resistance flag which means the DRGB is
+         reseeded from the TRNG every time random data is generated.
+
+endif
index cfb36f3..a5e8d38 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
 obj-$(CONFIG_CMD_BLOB) += fsl_blob.o
 obj-$(CONFIG_CMD_DEKBLOB) += fsl_blob.o
 obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
+obj-$(CONFIG_FSL_CAAM_RNG) += rng.o
index a888758..fbc1aed 100644 (file)
@@ -296,6 +296,16 @@ void inline_cnstr_jobdesc_rng_deinstantiation(u32 *desc, int handle)
                         (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL);
 }
 
+void inline_cnstr_jobdesc_rng(u32 *desc, void *data_out, u32 size)
+{
+       dma_addr_t dma_data_out = virt_to_phys(data_out);
+
+       init_job_desc(desc, 0);
+       append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG |
+                        OP_ALG_PR_ON);
+       append_fifo_store(desc, dma_data_out, size, FIFOST_TYPE_RNGSTORE);
+}
+
 /* Change key size to bytes form bits in calling function*/
 void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
                                      struct pk_in_params *pkin, uint8_t *out,
index 5185ddd..c4501ab 100644 (file)
@@ -43,7 +43,10 @@ void inline_cnstr_jobdesc_rng_instantiation(u32 *desc, int handle, int do_sk);
 
 void inline_cnstr_jobdesc_rng_deinstantiation(u32 *desc, int handle);
 
+void inline_cnstr_jobdesc_rng(u32 *desc, void *data_out, u32 size);
+
 void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
                                      struct pk_in_params *pkin, uint8_t *out,
                                      uint32_t out_siz);
+
 #endif
index c5802f7..44273c3 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/cache.h>
 #include <asm/fsl_pamu.h>
 #endif
+#include <dm/lists.h>
 
 #define CIRC_CNT(head, tail, size)     (((head) - (tail)) & (size - 1))
 #define CIRC_SPACE(head, tail, size)   CIRC_CNT((tail), (head) + 1, (size))
@@ -721,6 +722,14 @@ int sec_init_idx(uint8_t sec_idx)
                        printf("SEC%u:  RNG instantiation failed\n", sec_idx);
                        return -1;
                }
+
+               if (IS_ENABLED(CONFIG_DM_RNG)) {
+                       ret = device_bind_driver(NULL, "caam-rng", "caam-rng",
+                                                NULL);
+                       if (ret)
+                               printf("Couldn't bind rng driver (%d)\n", ret);
+               }
+
                printf("SEC%u:  RNG instantiated\n", sec_idx);
        }
 #endif
diff --git a/drivers/crypto/fsl/rng.c b/drivers/crypto/fsl/rng.c
new file mode 100644 (file)
index 0000000..3c0c2b0
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Michael Walle <michael@walle.cc>
+ *
+ * Driver for Freescale Cryptographic Accelerator and Assurance
+ * Module (CAAM) hardware random number generator.
+ */
+
+#include <asm/cache.h>
+#include <common.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <rng.h>
+#include <linux/kernel.h>
+#include "desc_constr.h"
+#include "jobdesc.h"
+#include "jr.h"
+
+#define CAAM_RNG_MAX_FIFO_STORE_SIZE 16
+#define CAAM_RNG_DESC_LEN (3 * CAAM_CMD_SZ + CAAM_PTR_SZ)
+
+struct caam_rng_priv {
+       u32 desc[CAAM_RNG_DESC_LEN / 4];
+       u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN);
+};
+
+static int caam_rng_read_one(struct caam_rng_priv *priv)
+{
+       int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN);
+       int ret;
+
+       ret = run_descriptor_jr(priv->desc);
+       if (ret < 0)
+               return -EIO;
+
+       invalidate_dcache_range((unsigned long)priv->data,
+                               (unsigned long)priv->data + size);
+
+       return 0;
+}
+
+static int caam_rng_read(struct udevice *dev, void *data, size_t len)
+{
+       struct caam_rng_priv *priv = dev_get_priv(dev);
+       u8 *buffer = data;
+       size_t size;
+       int ret;
+
+       while (len) {
+               ret = caam_rng_read_one(priv);
+               if (ret)
+                       return ret;
+
+               size = min(len, (size_t)CAAM_RNG_MAX_FIFO_STORE_SIZE);
+
+               memcpy(buffer, priv->data, size);
+               buffer += size;
+               len -= size;
+       }
+
+       return 0;
+}
+
+static int caam_rng_probe(struct udevice *dev)
+{
+       struct caam_rng_priv *priv = dev_get_priv(dev);
+       ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN);
+
+       inline_cnstr_jobdesc_rng(priv->desc, priv->data,
+                                CAAM_RNG_MAX_FIFO_STORE_SIZE);
+       flush_dcache_range((unsigned long)priv->desc,
+                          (unsigned long)priv->desc + size);
+
+       return 0;
+}
+
+static const struct dm_rng_ops caam_rng_ops = {
+       .read = caam_rng_read,
+};
+
+U_BOOT_DRIVER(caam_rng) = {
+       .name = "caam-rng",
+       .id = UCLASS_RNG,
+       .ops = &caam_rng_ops,
+       .probe = caam_rng_probe,
+       .priv_auto_alloc_size = sizeof(struct caam_rng_priv),
+       .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};