summaryrefslogtreecommitdiff
path: root/drivers/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto')
-rw-r--r--drivers/crypto/fsl/Kconfig14
-rw-r--r--drivers/crypto/fsl/Makefile1
-rw-r--r--drivers/crypto/fsl/desc.h2
-rw-r--r--drivers/crypto/fsl/desc_constr.h27
-rw-r--r--drivers/crypto/fsl/fsl_hash.c2
-rw-r--r--drivers/crypto/fsl/jobdesc.c30
-rw-r--r--drivers/crypto/fsl/jobdesc.h7
-rw-r--r--drivers/crypto/fsl/jr.c111
-rw-r--r--drivers/crypto/fsl/rng.c88
-rw-r--r--drivers/crypto/fsl/sec.c10
10 files changed, 251 insertions, 41 deletions
diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
index 181a1e5e99c..5ed6140da35 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 cfb36f3bb9b..a5e8d38e381 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/desc.h b/drivers/crypto/fsl/desc.h
index 11ad506829f..3589e6ea024 100644
--- a/drivers/crypto/fsl/desc.h
+++ b/drivers/crypto/fsl/desc.h
@@ -520,6 +520,8 @@
#define OP_ALG_ICV_OFF (0 << OP_ALG_ICV_SHIFT)
#define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT)
+#define OP_ALG_PR_ON 0x02
+
#define OP_ALG_DIR_SHIFT 0
#define OP_ALG_DIR_MASK 1
#define OP_ALG_DECRYPT 0
diff --git a/drivers/crypto/fsl/desc_constr.h b/drivers/crypto/fsl/desc_constr.h
index cb112283aca..b82ba83e73a 100644
--- a/drivers/crypto/fsl/desc_constr.h
+++ b/drivers/crypto/fsl/desc_constr.h
@@ -36,19 +36,16 @@
(LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
#ifdef CONFIG_PHYS_64BIT
-union ptr_addr_t {
- u64 m_whole;
- struct {
+struct ptr_addr_t {
#ifdef CONFIG_SYS_FSL_SEC_LE
- u32 low;
- u32 high;
+ u32 low;
+ u32 high;
#elif defined(CONFIG_SYS_FSL_SEC_BE)
- u32 high;
- u32 low;
+ u32 high;
+ u32 low;
#else
#error Neither CONFIG_SYS_FSL_SEC_LE nor CONFIG_SYS_FSL_SEC_BE is defined
#endif
- } m_halfs;
};
#endif
@@ -57,9 +54,10 @@ static inline void pdb_add_ptr(dma_addr_t *offset, dma_addr_t ptr)
#ifdef CONFIG_PHYS_64BIT
/* The Position of low and high part of 64 bit address
* will depend on the endianness of CAAM Block */
- union ptr_addr_t *ptr_addr = (union ptr_addr_t *)offset;
- ptr_addr->m_halfs.high = (u32)(ptr >> 32);
- ptr_addr->m_halfs.low = (u32)ptr;
+ struct ptr_addr_t *ptr_addr = (struct ptr_addr_t *)offset;
+
+ ptr_addr->high = (u32)(ptr >> 32);
+ ptr_addr->low = (u32)ptr;
#else
*offset = ptr;
#endif
@@ -111,9 +109,10 @@ static inline void append_ptr(u32 *desc, dma_addr_t ptr)
#ifdef CONFIG_PHYS_64BIT
/* The Position of low and high part of 64 bit address
* will depend on the endianness of CAAM Block */
- union ptr_addr_t *ptr_addr = (union ptr_addr_t *)offset;
- ptr_addr->m_halfs.high = (u32)(ptr >> 32);
- ptr_addr->m_halfs.low = (u32)ptr;
+ struct ptr_addr_t *ptr_addr = (struct ptr_addr_t *)offset;
+
+ ptr_addr->high = (u32)(ptr >> 32);
+ ptr_addr->low = (u32)ptr;
#else
*offset = ptr;
#endif
diff --git a/drivers/crypto/fsl/fsl_hash.c b/drivers/crypto/fsl/fsl_hash.c
index 953deec9ff7..61f953e8a6d 100644
--- a/drivers/crypto/fsl/fsl_hash.c
+++ b/drivers/crypto/fsl/fsl_hash.c
@@ -86,7 +86,7 @@ static int caam_hash_update(void *hash_ctx, const void *buf,
unsigned int size, int is_last,
enum caam_hash_algos caam_algo)
{
- uint32_t final = 0;
+ uint32_t final;
phys_addr_t addr = virt_to_phys((void *)buf);
struct sha_ctx *ctx = hash_ctx;
diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c
index 2f35e0c90b8..fbc1aeddeeb 100644
--- a/drivers/crypto/fsl/jobdesc.c
+++ b/drivers/crypto/fsl/jobdesc.c
@@ -102,8 +102,8 @@ int caam_page_alloc(uint8_t page_num, uint8_t partition_num)
/* if the page is not owned => problem */
if ((temp_reg & SMCSJR_PO) != PAGE_OWNED) {
- printf("Allocation of page %d in partition %d failed 0x%X\n",
- temp_reg, page_num, partition_num);
+ printf("Allocation of page %u in partition %u failed 0x%X\n",
+ page_num, partition_num, temp_reg);
return ERROR_IN_PAGE_ALLOC;
}
@@ -258,7 +258,7 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
* Descriptor to instantiate RNG State Handle 0 in normal mode and
* load the JDKEK, TDKEK and TDSK registers
*/
-void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle)
+void inline_cnstr_jobdesc_rng_instantiation(u32 *desc, int handle, int do_sk)
{
u32 *jump_cmd;
@@ -266,10 +266,11 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle)
/* INIT RNG in non-test mode */
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
- (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT);
+ (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT |
+ OP_ALG_PR_ON);
/* For SH0, Secure Keys must be generated as well */
- if (handle == 0) {
+ if (!handle && do_sk) {
/* wait for done */
jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
set_jump_tgt_here(desc, jump_cmd);
@@ -286,6 +287,25 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle)
}
}
+/* Descriptor for deinstantiation of the RNG block. */
+void inline_cnstr_jobdesc_rng_deinstantiation(u32 *desc, int handle)
+{
+ init_job_desc(desc, 0);
+
+ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
+ (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 d782c46b9db..c4501abd26b 100644
--- a/drivers/crypto/fsl/jobdesc.h
+++ b/drivers/crypto/fsl/jobdesc.h
@@ -39,9 +39,14 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
uint8_t *enc_blob, uint8_t *plain_txt,
uint32_t out_sz);
-void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle);
+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 e2d9216cfc7..44273c345f9 100644
--- a/drivers/crypto/fsl/jr.c
+++ b/drivers/crypto/fsl/jr.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <cpu_func.h>
+#include <linux/kernel.h>
#include <log.h>
#include <malloc.h>
#include "fsl_sec.h"
@@ -19,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))
@@ -446,7 +448,52 @@ int sec_reset(void)
return sec_reset_idx(0);
}
#ifndef CONFIG_SPL_BUILD
-static int instantiate_rng(uint8_t sec_idx)
+static int deinstantiate_rng(u8 sec_idx, int state_handle_mask)
+{
+ u32 *desc;
+ int sh_idx, ret = 0;
+ int desc_size = ALIGN(sizeof(u32) * 2, ARCH_DMA_MINALIGN);
+
+ desc = memalign(ARCH_DMA_MINALIGN, desc_size);
+ if (!desc) {
+ debug("cannot allocate RNG init descriptor memory\n");
+ return -ENOMEM;
+ }
+
+ for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
+ /*
+ * If the corresponding bit is set, then it means the state
+ * handle was initialized by us, and thus it needs to be
+ * deinitialized as well
+ */
+
+ if (state_handle_mask & RDSTA_IF(sh_idx)) {
+ /*
+ * Create the descriptor for deinstantating this state
+ * handle.
+ */
+ inline_cnstr_jobdesc_rng_deinstantiation(desc, sh_idx);
+ flush_dcache_range((unsigned long)desc,
+ (unsigned long)desc + desc_size);
+
+ ret = run_descriptor_jr_idx(desc, sec_idx);
+ if (ret) {
+ printf("SEC%u: RNG4 SH%d deinstantiation failed with error 0x%x\n",
+ sec_idx, sh_idx, ret);
+ ret = -EIO;
+ break;
+ }
+
+ printf("SEC%u: Deinstantiated RNG4 SH%d\n",
+ sec_idx, sh_idx);
+ }
+ }
+
+ free(desc);
+ return ret;
+}
+
+static int instantiate_rng(u8 sec_idx, int gen_sk)
{
u32 *desc;
u32 rdsta_val;
@@ -466,11 +513,20 @@ static int instantiate_rng(uint8_t sec_idx)
* If the corresponding bit is set, this state handle
* was initialized by somebody else, so it's left alone.
*/
- rdsta_val = sec_in32(&rng->rdsta) & RNG_STATE_HANDLE_MASK;
- if (rdsta_val & (1 << sh_idx))
- continue;
+ rdsta_val = sec_in32(&rng->rdsta);
+ if (rdsta_val & (RDSTA_IF(sh_idx))) {
+ if (rdsta_val & RDSTA_PR(sh_idx))
+ continue;
+
+ printf("SEC%u: RNG4 SH%d was instantiated w/o prediction resistance. Tearing it down\n",
+ sec_idx, sh_idx);
- inline_cnstr_jobdesc_rng_instantiation(desc, sh_idx);
+ ret = deinstantiate_rng(sec_idx, RDSTA_IF(sh_idx));
+ if (ret)
+ break;
+ }
+
+ inline_cnstr_jobdesc_rng_instantiation(desc, sh_idx, gen_sk);
size = roundup(sizeof(uint32_t) * 6, ARCH_DMA_MINALIGN);
flush_dcache_range((unsigned long)desc,
(unsigned long)desc + size);
@@ -478,11 +534,11 @@ static int instantiate_rng(uint8_t sec_idx)
ret = run_descriptor_jr_idx(desc, sec_idx);
if (ret)
- printf("RNG: Instantiation failed with error 0x%x\n",
- ret);
+ printf("SEC%u: RNG4 SH%d instantiation failed with error 0x%x\n",
+ sec_idx, sh_idx, ret);
- rdsta_val = sec_in32(&rng->rdsta) & RNG_STATE_HANDLE_MASK;
- if (!(rdsta_val & (1 << sh_idx))) {
+ rdsta_val = sec_in32(&rng->rdsta);
+ if (!(rdsta_val & RDSTA_IF(sh_idx))) {
free(desc);
return -1;
}
@@ -498,9 +554,17 @@ static int instantiate_rng(uint8_t sec_idx)
static u8 get_rng_vid(uint8_t sec_idx)
{
ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx);
- u32 cha_vid = sec_in32(&sec->chavid_ls);
+ u8 vid;
+
+ if (caam_get_era() < 10) {
+ vid = (sec_in32(&sec->chavid_ls) & SEC_CHAVID_RNG_LS_MASK)
+ >> SEC_CHAVID_LS_RNG_SHIFT;
+ } else {
+ vid = (sec_in32(&sec->vreg.rng) & CHA_VER_VID_MASK)
+ >> CHA_VER_VID_SHIFT;
+ }
- return (cha_vid & SEC_CHAVID_RNG_LS_MASK) >> SEC_CHAVID_LS_RNG_SHIFT;
+ return vid;
}
/*
@@ -538,14 +602,15 @@ static void kick_trng(int ent_delay, uint8_t sec_idx)
static int rng_init(uint8_t sec_idx)
{
- int ret, ent_delay = RTSDCTL_ENT_DLY_MIN;
+ int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
ccsr_sec_t __iomem *sec = (ccsr_sec_t __iomem *)SEC_ADDR(sec_idx);
struct rng4tst __iomem *rng =
(struct rng4tst __iomem *)&sec->rng;
u32 inst_handles;
+ gen_sk = !(sec_in32(&rng->rdsta) & RDSTA_SKVN);
do {
- inst_handles = sec_in32(&rng->rdsta) & RNG_STATE_HANDLE_MASK;
+ inst_handles = sec_in32(&rng->rdsta) & RDSTA_MASK;
/*
* If either of the SH's were instantiated by somebody else
@@ -566,10 +631,10 @@ static int rng_init(uint8_t sec_idx)
* interval, leading to a sucessful initialization of
* the RNG.
*/
- ret = instantiate_rng(sec_idx);
+ ret = instantiate_rng(sec_idx, gen_sk);
} while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
if (ret) {
- printf("RNG: Failed to instantiate RNG\n");
+ printf("SEC%u: Failed to instantiate RNG\n", sec_idx);
return ret;
}
@@ -592,7 +657,7 @@ int sec_init_idx(uint8_t sec_idx)
#endif
if (!(sec_idx < CONFIG_SYS_FSL_MAX_NUM_OF_SEC)) {
- printf("SEC initialization failed\n");
+ printf("SEC%u: initialization failed\n", sec_idx);
return -1;
}
@@ -640,7 +705,7 @@ int sec_init_idx(uint8_t sec_idx)
ret = jr_init(sec_idx);
if (ret < 0) {
- printf("SEC initialization failed\n");
+ printf("SEC%u: initialization failed\n", sec_idx);
return -1;
}
@@ -654,10 +719,18 @@ int sec_init_idx(uint8_t sec_idx)
#ifndef CONFIG_SPL_BUILD
if (get_rng_vid(sec_idx) >= 4) {
if (rng_init(sec_idx) < 0) {
- printf("SEC%u: RNG instantiation failed\n", sec_idx);
+ printf("SEC%u: RNG instantiation failed\n", sec_idx);
return -1;
}
- printf("SEC%u: RNG instantiated\n", sec_idx);
+
+ 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
return ret;
diff --git a/drivers/crypto/fsl/rng.c b/drivers/crypto/fsl/rng.c
new file mode 100644
index 00000000000..3c0c2b067f3
--- /dev/null
+++ b/drivers/crypto/fsl/rng.c
@@ -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,
+};
diff --git a/drivers/crypto/fsl/sec.c b/drivers/crypto/fsl/sec.c
index a2c0bfaf44c..f0a4a63d886 100644
--- a/drivers/crypto/fsl/sec.c
+++ b/drivers/crypto/fsl/sec.c
@@ -98,7 +98,15 @@ void fdt_fixup_crypto_node(void *blob, int sec_rev)
fdt_strerror(err));
}
#elif CONFIG_SYS_FSL_SEC_COMPAT >= 4 /* SEC4 */
-static u8 caam_get_era(void)
+/**
+ * caam_get_era() - fetch the CAAM's era
+ *
+ * The SEC module povides an "Era" which can be used to differentiate
+ * between different revisions.
+ *
+ * Return: era of the SEC.
+ */
+u8 caam_get_era(void)
{
static const struct {
u16 ip_id;