diff options
Diffstat (limited to 'drivers/crypto/caam/rng_self_test.c')
-rw-r--r-- | drivers/crypto/caam/rng_self_test.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/crypto/caam/rng_self_test.c b/drivers/crypto/caam/rng_self_test.c new file mode 100644 index 0000000000..aab4fa2e47 --- /dev/null +++ b/drivers/crypto/caam/rng_self_test.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2018 NXP + * Copyright (C) 2018 Pengutronix, Roland Hieber <r.hieber@pengutronix.de> + * + * CAAM RNG self-test -- based on the vendor patch for U-Boot: + * https://portland.source.codeaurora.org/patches/external/imxsupport/uboot-imx/imx_v2016.03_4.1.15_2.0.0_ga/HAB-238-Run-RNG-self-test-for-impacted-i.MX-chips.zip + * + * | From: Utkarsh Gupta <utkarsh.gupta@nxp.com> + * | Subject: [PATCH] HAB-238 Run RNG self test for impacted i.MX chips + * | + * | Patch is only applicable to imx_v2016.03_4.1.15_2.0.0_ga branch of u-boot. + * | Please adapt the patch for your respective release version. + * | + * | Background: + * | Few i.MX chips which have HAB 4.2.3 or beyond, have oberserved following + * | warning message generated by HAB due to incorrect implementation of drng + * | self test in boot ROM. + * | + * | Event |0xdb|0x0024|0x42| SRCE Field: 69 30 e1 1d + * | | | | | STS = HAB_WARNING (0x69) + * | | | | | RSN = HAB_ENG_FAIL (0x30) + * | | | | | CTX = HAB_CTX_ENTRY (0xE1) + * | | | | | ENG = HAB_ENG_CAAM (0x1D) + * | | | | | Evt Data (hex): + * | | | | | 00 08 00 02 40 00 36 06 55 55 00 03 00 00 00 00 + * | | | | | 00 00 00 00 00 00 00 00 00 00 00 01 + * | + * | It is recommended to run this rng self test before any RNG related crypto + * | implementations are done. + * [...] + * | + * | Signed-off-by: Utkarsh Gupta <utkarsh.gupta@nxp.com> + * + * Known impacted chips: + * + * - i.MX6DQ+ silicon revision 1.1 + * - i.MX6DQ silicon revision 1.6 + * - i.MX6DLS silicon revision 1.4 + * - i.MX6SX silicon revision 1.4 + * - i.MX6UL silicon revision 1.2 + * - i.MX67SD silicon revision 1.3 + */ + +#define pr_fmt(fmt) "rng_self_test: " fmt + +#include <dma.h> +#include <common.h> +#include <linux/kernel.h> + +#include "error.h" +#include "regs.h" +#include "jr.h" + +static const u32 rng_dsc1[] = { + 0xb0800036, 0x04800010, 0x3c85a15b, 0x50a9d0b1, + 0x71a09fee, 0x2eecf20b, 0x02800020, 0xb267292e, + 0x85bf712d, 0xe85ff43a, 0xa716b7fb, 0xc40bb528, + 0x27b6f564, 0x8821cb5d, 0x9b5f6c26, 0x12a00020, + 0x0a20de17, 0x6529357e, 0x316277ab, 0x2846254e, + 0x34d23ba5, 0x6f5e9c32, 0x7abdc1bb, 0x0197a385, + 0x82500405, 0xa2000001, 0x10880004, 0x00000005, + 0x12820004, 0x00000020, 0x82500001, 0xa2000001, + 0x10880004, 0x40000045, 0x02800020, 0x8f389cc7, + 0xe7f7cbb0, 0x6bf2073d, 0xfc380b6d, 0xb22e9d1a, + 0xee64fcb7, 0xa2b48d49, 0xdf9bc3a4, 0x82500009, + 0xa2000001, 0x10880004, 0x00000005, 0x82500001, + 0x60340020, 0xFFFFFFFF, 0xa2000001, 0x10880004, + 0x00000005, 0x8250000d +}; + +static const u8 rng_result1[] = { + 0x3a, 0xfe, 0x2c, 0x87, 0xcc, 0xb6, 0x44, 0x49, + 0x19, 0x16, 0x9a, 0x74, 0xa1, 0x31, 0x8b, 0xef, + 0xf4, 0x86, 0x0b, 0xb9, 0x5e, 0xee, 0xae, 0x91, + 0x92, 0xf4, 0xa9, 0x8f, 0xb0, 0x37, 0x18, 0xa4 +}; + +static const u32 rng_dsc2[] = { + 0xb080003a, 0x04800020, 0x27b73130, 0x30b4b10f, + 0x7c62b1ad, 0x77abe899, 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, 0x02800020, 0x63f757cf, + 0xb9165584, 0xc3c1b407, 0xcc4ce8ad, 0x1ffe8a58, + 0xfb4fa893, 0xbb5f4af0, 0x3fb946a1, 0x12a00020, + 0x56cbcaa5, 0xfff3adad, 0xe804dcbf, 0x9a900c71, + 0xa42017e3, 0x826948e2, 0xd0cfeb3e, 0xaf1a136a, + 0x82500405, 0xa2000001, 0x10880004, 0x00000005, + 0x12820004, 0x00000020, 0x82500001, 0xa2000001, + 0x10880004, 0x40000045, 0x02800020, 0x2e882f8a, + 0xe929943e, 0x8132c0a8, 0x12037f90, 0x809fbd66, + 0x8684ea04, 0x00cbafa7, 0x7b82d12a, 0x82500009, + 0xa2000001, 0x10880004, 0x00000005, 0x82500001, + 0x60340020, 0xFFFFFFFF, 0xa2000001, 0x10880004, + 0x00000005, 0x8250000d +}; + +static const u8 rng_result2[] = { + 0x76, 0x87, 0x66, 0x4e, 0xd8, 0x1d, 0x1f, 0x43, + 0x76, 0x50, 0x85, 0x5d, 0x1e, 0x1d, 0x9d, 0x0f, + 0x93, 0x75, 0x83, 0xff, 0x9a, 0x9b, 0x61, 0xa9, + 0xa5, 0xeb, 0xa3, 0x28, 0x2a, 0x15, 0xc1, 0x57 +}; + +/* + * construct_rng_self_test_jobdesc() - Implement destination address in RNG self test descriptors + * Returns zero on success, and negative on error. + */ +static void construct_rng_self_test_jobdesc(u32 *desc, const u32 *rng_st_dsc, u8 *res_addr, int desc_size) +{ + int result_addr_idx = desc_size - 5; + int i; + + for (i = 0; i < desc_size; i++) { + desc[i] = rng_st_dsc[i]; + } + + /* Replace destination address in the descriptor */ + desc[result_addr_idx] = (u32)res_addr; +} + +/* rng_self_test_done() - callback for caam_jr_enqueue */ +static void rng_self_test_done(struct device_d *dev, u32 *desc, u32 err, void *arg) +{ + int * job_err = arg; + *job_err = err; +} + +/* + * caam_rng_self_test() - Perform RNG self test + * Returns zero on success, and negative on error. + */ +int caam_rng_self_test(struct device_d *dev, const u8 caam_era, const u8 rngvid, const u8 rngrev) +{ + int ret, desc_size = 0, result_size = 0, job_err = 0; + const u32 *rng_st_dsc; + const u8 *exp_result; + u32 *desc; + u8 *result; + + pr_debug("got CAAM ERA %d, RNG Version ID %d, RNG revision %d\n", + caam_era, rngvid, rngrev); + + if (caam_era < 8 && rngvid == 4 && rngrev < 3) { + /* older affected i.MX chipsets have CAAM < 8 and have RNG4 < 4.3 */ + rng_st_dsc = rng_dsc1; + desc_size = ARRAY_SIZE(rng_dsc1); + exp_result = rng_result1; + result_size = ARRAY_SIZE(rng_result1); + } else if (caam_era >= 8 || (rngvid >= 4 && rngrev >= 3)) { + /* newer affected chipsets have CAAM >= 8 or RNG4 >= 4.3 */ + rng_st_dsc = rng_dsc2; + desc_size = ARRAY_SIZE(rng_dsc2); + exp_result = rng_result2; + result_size = ARRAY_SIZE(rng_result2); + } else { + pr_err("Invalid CAAM version: %d,%d,%d\n", + caam_era, rngvid, rngrev); + return -EINVAL; + } + + result = dma_alloc(sizeof(*result) * result_size); + desc = dma_alloc(sizeof(*desc) * desc_size); + + if (!result || !desc) { + ret = -ENOMEM; + goto err; + } + + construct_rng_self_test_jobdesc(desc, rng_st_dsc, result, desc_size); + + dma_sync_single_for_device((unsigned long)desc, + desc_size * sizeof(*desc), DMA_TO_DEVICE); + dma_sync_single_for_device((unsigned long)result, + result_size * sizeof(*result), DMA_FROM_DEVICE); + + /* wait for job completion */ + ret = caam_jr_enqueue(dev, desc, rng_self_test_done, &job_err); + if (ret) { + pr_err("Running RNG self-test descriptor failed: %d %s\n", + ret, strerror(ret)); + goto err; + } + if (job_err) { + ret = -EINVAL; + pr_err("Job Error:\n"); + caam_jr_strstatus(dev, job_err); + goto err; + } + + dma_sync_single_for_cpu((unsigned long)result, result_size * sizeof(*result), + DMA_FROM_DEVICE); + + if (memcmp(result, exp_result, sizeof(*result) * result_size) != 0) { + pr_err("RNG self-test failed with unexpected result\n"); + ret = -ERANGE; + goto err; + } + + pr_info("RNG software self-test passed\n"); + ret = 0; + +err: + dma_free(desc); + dma_free(result); + return ret; +} |