diff mbox series

[v3,6/6] crypto/fsl: add RNG support

Message ID 20200625121905.4475-7-michael@walle.cc
State Superseded
Headers show
Series crypto/fsl: add RNG support | expand

Commit Message

Michael Walle June 25, 2020, 12:19 p.m. UTC
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 at walle.cc>
---
 drivers/crypto/fsl/Kconfig   | 14 ++++++
 drivers/crypto/fsl/Makefile  |  1 +
 drivers/crypto/fsl/jobdesc.c | 10 +++++
 drivers/crypto/fsl/jobdesc.h |  3 ++
 drivers/crypto/fsl/jr.c      |  9 ++++
 drivers/crypto/fsl/rng.c     | 86 ++++++++++++++++++++++++++++++++++++
 6 files changed, 123 insertions(+)
 create mode 100644 drivers/crypto/fsl/rng.c

Comments

Heinrich Schuchardt June 25, 2020, 1:19 p.m. UTC | #1
On 25.06.20 14:19, Michael Walle wrote:
> 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 at walle.cc>
> ---
>  drivers/crypto/fsl/Kconfig   | 14 ++++++
>  drivers/crypto/fsl/Makefile  |  1 +
>  drivers/crypto/fsl/jobdesc.c | 10 +++++
>  drivers/crypto/fsl/jobdesc.h |  3 ++
>  drivers/crypto/fsl/jr.c      |  9 ++++
>  drivers/crypto/fsl/rng.c     | 86 ++++++++++++++++++++++++++++++++++++
>  6 files changed, 123 insertions(+)
>  create mode 100644 drivers/crypto/fsl/rng.c
>
> diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
> index 181a1e5e99..5ed6140da3 100644
> --- a/drivers/crypto/fsl/Kconfig
> +++ b/drivers/crypto/fsl/Kconfig
> @@ -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

Should FSL_CAAM imply DM_RNG? This way you would not have to update the
defconfigs of the NXP boards.

For new files there should be a maintainer. It would be great if
somebody at NXP could take charge of the drivers/crypto/fsl directory.

Best regards

Heinrich
Heinrich Schuchardt June 26, 2020, 5:32 p.m. UTC | #2
On 6/25/20 2:19 PM, Michael Walle wrote:
> 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 at walle.cc>
> ---
>  drivers/crypto/fsl/Kconfig   | 14 ++++++
>  drivers/crypto/fsl/Makefile  |  1 +
>  drivers/crypto/fsl/jobdesc.c | 10 +++++
>  drivers/crypto/fsl/jobdesc.h |  3 ++
>  drivers/crypto/fsl/jr.c      |  9 ++++
>  drivers/crypto/fsl/rng.c     | 86 ++++++++++++++++++++++++++++++++++++
>  6 files changed, 123 insertions(+)
>  create mode 100644 drivers/crypto/fsl/rng.c
>
> diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
> index 181a1e5e99..5ed6140da3 100644
> --- a/drivers/crypto/fsl/Kconfig
> +++ b/drivers/crypto/fsl/Kconfig
> @@ -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
> diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
> index cfb36f3bb9..a5e8d38e38 100644
> --- a/drivers/crypto/fsl/Makefile
> +++ b/drivers/crypto/fsl/Makefile
> @@ -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
> diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c
> index d9554c550b..decde64078 100644
> --- a/drivers/crypto/fsl/jobdesc.c
> +++ b/drivers/crypto/fsl/jobdesc.c
> @@ -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,
> diff --git a/drivers/crypto/fsl/jobdesc.h b/drivers/crypto/fsl/jobdesc.h
> index 5185ddd535..c4501abd26 100644
> --- a/drivers/crypto/fsl/jobdesc.h
> +++ b/drivers/crypto/fsl/jobdesc.h
> @@ -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
> diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c
> index 00a3244b18..9ada1d625b 100644
> --- a/drivers/crypto/fsl/jr.c
> +++ b/drivers/crypto/fsl/jr.c
> @@ -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
> index 0000000000..136b2cdcd7
> --- /dev/null
> +++ b/drivers/crypto/fsl/rng.c
> @@ -0,0 +1,86 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2020 Michael Walle <michael at 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 "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_platdata {
> +	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_platdata *pdata)
> +{
> +	int size = CAAM_RNG_MAX_FIFO_STORE_SIZE;

This should be

int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN);



> +	int ret;
> +
> +	ret = run_descriptor_jr(pdata->desc);
> +	if (ret < 0)
> +		return -EIO;
> +
> +	invalidate_dcache_range((unsigned long)pdata->data,
> +				(unsigned long)pdata->data + size);

This fails on the i.MX6 Wandboard with

CACHE: Misaligned operation at range [8e596f68, 8e596f78]

because pdata is not ARCH_DMA_MINALIGN aligned.

> +
> +	return 0;
> +}
> +
> +static int caam_rng_read(struct udevice *dev, void *data, size_t len)
> +{
> +	struct caam_rng_platdata *pdata = dev_get_platdata(dev);
> +	u8 *buffer = data;
> +	size_t size;
> +	int ret;
> +
> +	while (len) {
> +		ret = caam_rng_read_one(pdata);
> +		if (ret)
> +			return ret;
> +
> +		size = min(len, (size_t)CAAM_RNG_MAX_FIFO_STORE_SIZE);
> +
> +		memcpy(buffer, pdata->data, size);
> +		buffer += size;
> +		len -= size;
> +	}
> +
> +	return 0;
> +}
> +
> +static int caam_rng_probe(struct udevice *dev)
> +{
> +	struct caam_rng_platdata *pdata = dev_get_platdata(dev);
> +
> +	inline_cnstr_jobdesc_rng(pdata->desc, pdata->data,
> +				 CAAM_RNG_MAX_FIFO_STORE_SIZE);
> +	flush_dcache_range((unsigned long)pdata->desc,
> +			   (unsigned long)pdata->desc + CAAM_RNG_DESC_LEN);

You should round CAAM_RNG_DESC_LEN up to a multiple of ARCH_DMA_MINALIGN.

> +
> +	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,
> +	.platdata_auto_alloc_size = sizeof(struct caam_rng_platdata),
> +	.flags = DM_FLAG_ALLOC_PRIV_DMA,

This flag is for private data. It does not provide aligned platform data.

So you should use:

.priv_auto_alloc_size = sizeof(struct caam_rng_platdata),

and

struct caam_rng_priv *priv = dev_get_priv(dev)

Best regards

Heinrich

> +};
>
diff mbox series

Patch

diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
index 181a1e5e99..5ed6140da3 100644
--- a/drivers/crypto/fsl/Kconfig
+++ b/drivers/crypto/fsl/Kconfig
@@ -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
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
index cfb36f3bb9..a5e8d38e38 100644
--- a/drivers/crypto/fsl/Makefile
+++ b/drivers/crypto/fsl/Makefile
@@ -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
diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c
index d9554c550b..decde64078 100644
--- a/drivers/crypto/fsl/jobdesc.c
+++ b/drivers/crypto/fsl/jobdesc.c
@@ -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,
diff --git a/drivers/crypto/fsl/jobdesc.h b/drivers/crypto/fsl/jobdesc.h
index 5185ddd535..c4501abd26 100644
--- a/drivers/crypto/fsl/jobdesc.h
+++ b/drivers/crypto/fsl/jobdesc.h
@@ -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
diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c
index 00a3244b18..9ada1d625b 100644
--- a/drivers/crypto/fsl/jr.c
+++ b/drivers/crypto/fsl/jr.c
@@ -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
index 0000000000..136b2cdcd7
--- /dev/null
+++ b/drivers/crypto/fsl/rng.c
@@ -0,0 +1,86 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Michael Walle <michael at 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 "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_platdata {
+	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_platdata *pdata)
+{
+	int size = CAAM_RNG_MAX_FIFO_STORE_SIZE;
+	int ret;
+
+	ret = run_descriptor_jr(pdata->desc);
+	if (ret < 0)
+		return -EIO;
+
+	invalidate_dcache_range((unsigned long)pdata->data,
+				(unsigned long)pdata->data + size);
+
+	return 0;
+}
+
+static int caam_rng_read(struct udevice *dev, void *data, size_t len)
+{
+	struct caam_rng_platdata *pdata = dev_get_platdata(dev);
+	u8 *buffer = data;
+	size_t size;
+	int ret;
+
+	while (len) {
+		ret = caam_rng_read_one(pdata);
+		if (ret)
+			return ret;
+
+		size = min(len, (size_t)CAAM_RNG_MAX_FIFO_STORE_SIZE);
+
+		memcpy(buffer, pdata->data, size);
+		buffer += size;
+		len -= size;
+	}
+
+	return 0;
+}
+
+static int caam_rng_probe(struct udevice *dev)
+{
+	struct caam_rng_platdata *pdata = dev_get_platdata(dev);
+
+	inline_cnstr_jobdesc_rng(pdata->desc, pdata->data,
+				 CAAM_RNG_MAX_FIFO_STORE_SIZE);
+	flush_dcache_range((unsigned long)pdata->desc,
+			   (unsigned long)pdata->desc + CAAM_RNG_DESC_LEN);
+
+	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,
+	.platdata_auto_alloc_size = sizeof(struct caam_rng_platdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};