Hi Roland, On Sun, Nov 25, 2018 at 11:59:51PM +0100, Roland Hieber wrote: > diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c > index 9e62bd6fd6..14dfc7e827 100644 > --- a/drivers/crypto/caam/ctrl.c > +++ b/drivers/crypto/caam/ctrl.c > @@ -19,10 +19,13 @@ > #include "desc_constr.h" > #include "error.h" > #include "ctrl.h" > +#include "rng_self_test.h" > > bool caam_little_end; > EXPORT_SYMBOL(caam_little_end); > > +extern bool habv4_need_rng_software_self_test; Put the declaration into include/hab.h > + > /* > * Descriptor to instantiate RNG State Handle 0 in normal mode and > * load the JDKEK, TDKEK and TDSK registers > @@ -570,6 +573,25 @@ static int caam_probe(struct device_d *dev) > > cha_vid_ls = rd_reg32(&ctrl->perfmon.cha_id_ls); > > + /* habv4_need_rng_software_self_test is determined by habv4_get_status() */ > + if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_SELF_TEST) && > + habv4_need_rng_software_self_test) { > + u8 caam_era; > + u8 rngvid; > + u8 rngrev; > + > + caam_era = (rd_reg32(&ctrl->perfmon.ccb_id) & CCBVID_ERA_MASK) >> CCBVID_ERA_SHIFT; > + rngvid = (cha_vid_ls & CHAVID_LS_RNGVID_MASK) >> CHAVID_LS_RNGVID_SHIFT; > + rngrev = (rd_reg32(&ctrl->perfmon.cha_rev_ls) & CRNR_LS_RNGRN_MASK) >> CRNR_LS_RNGRN_SHIFT; > + > + pr_info("detected failure in CAAM RNG ROM self-test, running software self-test\n"); This looks unnecessary. You already printed the HAB failure event and the rng_self_test() will output the result. > + ret = rng_self_test(ctrlpriv->jrpdev[0], caam_era, rngvid, rngrev); > + if (ret != 0) { > + caam_remove(dev); > + return ret; > + } > + } > + > /* > * If SEC has RNG version >= 4 and RNG state handle has not been > * already instantiated, do RNG instantiation > diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h > index 6c9d6d75a0..19e7d6d7e4 100644 > --- a/drivers/crypto/caam/regs.h > +++ b/drivers/crypto/caam/regs.h > @@ -279,6 +279,8 @@ struct caam_perfmon { > > /* CAAM Hardware Instantiation Parameters fa0-fbf */ > u32 cha_rev_ms; /* CRNR - CHA Rev No. Most significant half*/ > +#define CRNR_LS_RNGRN_SHIFT 16 > +#define CRNR_LS_RNGRN_MASK (0xfull << CRNR_LS_RNGRN_SHIFT) > u32 cha_rev_ls; /* CRNR - CHA Rev No. Least significant half*/ > #define CTPR_MS_QI_SHIFT 25 > #define CTPR_MS_QI_MASK (0x1ull << CTPR_MS_QI_SHIFT) > @@ -311,6 +313,8 @@ struct caam_perfmon { > #define CCBVID_ERA_SHIFT 24 > u32 ccb_id; /* CCBVID - CCB Version ID */ > u32 cha_id_ms; /* CHAVID - CHA Version ID Most Significant*/ > +#define CHAVID_LS_RNGVID_SHIFT 16 > +#define CHAVID_LS_RNGVID_MASK (0xfull << CHAVID_LS_RNGVID_SHIFT) > u32 cha_id_ls; /* CHAVID - CHA Version ID Least Significant*/ > u32 cha_num_ms; /* CHANUM - CHA Number Most Significant */ > u32 cha_num_ls; /* CHANUM - CHA Number Least Significant*/ > diff --git a/drivers/crypto/caam/rng_self_test.c b/drivers/crypto/caam/rng_self_test.c > new file mode 100644 > index 0000000000..aff8f26cfd > --- /dev/null > +++ b/drivers/crypto/caam/rng_self_test.c > @@ -0,0 +1,235 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright 2018 NXP > + * Copyright (C) 2018 Pengutronix, Roland Hieber <r.hieber@xxxxxxxxxxxxxx> > + * > + * 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@xxxxxxx> > + * | 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@xxxxxxx> > + * > + * 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 "error.h" > +#include "regs.h" > +#include "jr.h" > + > +static inline u32 sec_in32(void *addr) > +{ > + return readl(addr); > +} This function is unused. > + > +#define DSC1SIZE 0x36 > +#define DSC2SIZE 0x3A > +#define RESULT_SIZE 32 > + > +static const u32 rng_dsc1[DSC1SIZE] = { > + 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 > +}; Making this an array with undetermined size and using ARRAY_SIZE on the array would make counting the elements unnecessary. > + > +static const u32 rng_result1[RESULT_SIZE] = { > + 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 > +}; same here. > + > +static const u32 rng_dsc2[DSC2SIZE] = { > + 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 u32 rng_result2[RESULT_SIZE] = { > + 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 > +}; Why is this u32 when only the lower 8 bits are ever used? Changing this to u8 would allow you to use memcmp to compare the result with the expeceted one. > + > +/* > + * construct_rng_self_test_jobdesc() - Implement destination address in RNG self test descriptors > + * Returns zero on success, and negative on error. > + */ > +static int 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 = 0; > + > + if (!desc) { > + return -EINVAL; > + } No need to check, this is already done in the caller. > + > + 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; > + > + pr_vdebug("RNG SELF TEST DESCRIPTOR:\n"); > + for (i = 0; i < desc_size; i++) { > + pr_vdebug("0x%08X\n", desc[i]); > + } > + > + return 0; > +} > + > +/* 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 = (int *)arg; unnecessary cast. > + BUG_ON(!job_err); This is unnecessary because you will get a nive crash dump in the next line when you dereference the NULL pointer. > + *job_err = err; > +} > + > +/* > + * rng_self_test() - Perform RNG self test > + * Returns zero on success, and negative on error. > + */ > +int rng_self_test(struct device_d *dev, const u8 caam_era, const u8 rngvid, const u8 rngrev) > +{ Please add a caam_ prefix. > + int ret, i, desc_size = 0, job_err = 0; > + const u32 *rng_st_dsc, *exp_result; > + u32 *desc = 0; No need to initialize. > + u8 *result = 0; ditto. > + if (caam_era < 8 && rngvid == 4 && rngrev < 3) { > + rng_st_dsc = rng_dsc1; > + desc_size = DSC1SIZE; > + exp_result = rng_result1; > + } else if (rngvid != 3) { > + rng_st_dsc = rng_dsc2; > + desc_size = DSC2SIZE; > + exp_result = rng_result2; > + } else { > + pr_err("Error: Invalid CAAM ERA (%d) or RNG Version ID (%d) or RNG revision (%d)\n", > + caam_era, rngvid, rngrev); > + return -EINVAL; Is this test really correct? Basically it says "We accept everything except rngvid == 3". > + > + result = dma_alloc(sizeof(uint32_t) * RESULT_SIZE); > + if (!result) { > + pr_err("Not enough memory for result buffer allocation\n"); > + return -ENOMEM; > + } Please no messages for usual allocation failures. "result" is never freed. > + > + desc = dma_alloc(sizeof(uint32_t) * desc_size); > + if (!desc) { > + pr_err("Not enough memory for descriptor allocation\n"); > + return -ENOMEM; > + } > + > + ret = construct_rng_self_test_jobdesc(desc, rng_st_dsc, result, desc_size); > + if (ret) { > + pr_err("Error in Job Descriptor Construction: %d %s\n", > + ret, strerror(ret)); > + goto err; > + } else { Not necessary to put the below code into an else {} path when you error out above. > + dma_sync_single_for_device((unsigned long)desc, > + desc_size * sizeof(uint32_t), DMA_TO_DEVICE); > + dma_sync_single_for_device((unsigned long)result, > + RESULT_SIZE * sizeof(uint32_t), DMA_FROM_DEVICE); > + > + /* wait for job completion */ > + ret = caam_jr_enqueue(dev, desc, rng_self_test_done, &job_err); > + if (ret) { > + pr_err("Error while running RNG self-test descriptor: %d %s\n", > + ret, strerror(ret)); > + goto err; > + } > + if (job_err) { > + pr_err("Job Error:\n"); > + caam_jr_strstatus(dev, job_err); > + goto err; > + } > + } > + > + dma_sync_single_for_cpu((unsigned long)result, RESULT_SIZE * sizeof(uint32_t), > + DMA_FROM_DEVICE); > + > + pr_vdebug("Result\n"); > + for (i = 0; i < RESULT_SIZE; i++) { > + pr_vdebug("%02X\n", result[i]); > + } > + > + pr_vdebug("Expected Result:\n"); > + for (i = 0; i < RESULT_SIZE; i++) { > + pr_vdebug("%02X\n", exp_result[i]); > + } Use memory_display to display this. Also this is only interesting if both differ, so better print it in the failure path. > + > + for (i = 0; i < RESULT_SIZE; i++) { > + if (result[i] != exp_result[i]) { > + pr_err("RNG self-test failed with unexpected result\n"); > + ret = -ERANGE; > + goto err; > + } > + } memcmp, as mentioned above. > + pr_notice("RNG software self-test passed\n"); > + ret = 0; > + > +err: > + dma_free(desc); > + return ret; > +} > diff --git a/drivers/crypto/caam/rng_self_test.h b/drivers/crypto/caam/rng_self_test.h > new file mode 100644 > index 0000000000..67356fe93b > --- /dev/null > +++ b/drivers/crypto/caam/rng_self_test.h > @@ -0,0 +1,24 @@ > +/* > + * CAAM RNG self test > + * > + * Copyright (C) 2018 Pengutronix, Roland Hieber <r.hieber@xxxxxxxxxxxxxx> > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#ifndef RNG_SELF_TEST_H > +#define RNG_SELF_TEST_H > + > +int rng_self_test(struct device_d *dev, const u8 caam_era, const u8 rngvid, const u8 rngrev); > + > +#endif /* RNG_SELF_TEST_H */ > diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c > index 28fd42ecd7..e64f34870e 100644 > --- a/drivers/hab/habv4.c > +++ b/drivers/hab/habv4.c > @@ -387,6 +387,27 @@ static void habv4_display_event(uint8_t *data, uint32_t len) > habv4_display_event_record((struct hab_event_record *)data); > } > > +/* Some chips with HAB >= 4.2.3 have an incorrect implementation of the RNG > + * self-test in ROM code. In this case, an HAB event is generated, and a > + * software self-test should be run. This variable is set to @c true by > + * habv4_get_status() when this occurs. */ > +bool habv4_need_rng_software_self_test = false; > +EXPORT_SYMBOL(habv4_need_rng_software_self_test); > + > +#define RNG_FAIL_EVENT_SIZE 36 ARRAY_SIZE is your friend. > +static uint8_t habv4_known_rng_fail_events[][RNG_FAIL_EVENT_SIZE] = { > + { 0xdb, 0x00, 0x24, 0x42, 0x69, 0x30, 0xe1, 0x1d, > + 0x00, 0x80, 0x00, 0x02, 0x40, 0x00, 0x36, 0x06, > + 0x55, 0x55, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, > + 0x00, 0x00, 0x00, 0x01 }, > + { 0xdb, 0x00, 0x24, 0x42, 0x69, 0x30, 0xe1, 0x1d, > + 0x00, 0x04, 0x00, 0x02, 0x40, 0x00, 0x36, 0x06, > + 0x55, 0x55, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, > + 0x00, 0x00, 0x00, 0x01 }, > +}; > + > static int habv4_get_status(const struct habv4_rvt *rvt) > { > uint8_t data[256]; > @@ -413,10 +434,29 @@ static int habv4_get_status(const struct habv4_rvt *rvt) > > len = sizeof(data); > while (rvt->report_event(HAB_STATUS_WARNING, index, data, &len) == HAB_STATUS_SUCCESS) { > - pr_err("-------- HAB warning Event %d --------\n", index); > - pr_err("event data:\n"); > > - habv4_display_event(data, len); > + /* suppress RNG self-test fail events if they can be handled in software */ > + bool is_rng_fail_event = false; > + if (IS_ENABLED(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_SELF_TEST)) { > + int i; > + for (i = 0; i < ARRAY_SIZE(habv4_known_rng_fail_events); i++) { > + if (memcmp(data, habv4_known_rng_fail_events[i], > + min(len, (uint32_t)RNG_FAIL_EVENT_SIZE)) == 0) { > + is_rng_fail_event = true; > + break; > + } > + } > + } You could put that into a separate function to make this loop body and also the test better readable. > + > + if (is_rng_fail_event) { > + pr_warning("RNG self-test failure detected, will run software self-test\n"); pr_warning is a bit harsh when we atually expect it. pr_info maybe? Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox