CryptoCell lazy initialization

nrf5340
NCS 3.1.0

Hello,

I am trying to improve boot time and here are some spikes and timings.


What I have found out is that CryptoCell init (hw_cc3xx_init_internal) takes majority of PRE_KERNEL_1 time.
As Crypto is not used early in the application, idea was to defer init of the driver, but I didn't had any success.

I've tried to comment out both SYS_INIT for hw_cc3xx_init (with and witout mutex), commented out entropy_cc3xx_rng_init, commented out _psa_crypto_init SYS_INIT and called those functions from main().
This is not working, board keeps rebooting

just for a test:
* I've tried to disable completely CC312 hardware and use Oberon instead without success.

* I've also tried to set zephyr,deferred-init; for &cryptocell. This just makes device disabled, but that 171ms function is still called in PRE_KERNEL_1

Do you have any recommendation how to make CryptoCell driver initialization later, during application run?
Thank you in advance,
Nemanja

  • Hello,

    I don't think it is possible with the current implementation, but I will investigate. Is your app using bluetooth? Reason for asking is that the stack requires the rng during init.

    Best regards,

    Vidar

  • Hello Vidar,
    Bluetooth is used, but also al later stage of the application.

    Basically Crypto and Bluetooth are used only to establish secure connection and transfer Firmware image for update.

    Thanks

  • HI  

    It seems like I succeeded.

    What I've changed:

    nrf/drivers/hw_cc3xx/hw_cc3xx.c

    // Removed this SYS_INIT calls and made hw_cc3xx_init global function
    /* Driver initalization done when mutex is not usable (pre kernel) */
    SYS_INIT(hw_cc3xx_init_internal, PRE_KERNEL_1,
    	 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
    
    /* Driver initialization when mutex is usable (post kernel) */
    SYS_INIT(hw_cc3xx_init, POST_KERNEL,
    	 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
    


    nrf/drivers/entropy/entropy_cc3xx.c

    // Changed this:
    DEVICE_DT_DEFINE(CRYPTOCELL_NODE_ID, entropy_cc3xx_rng_init,
    		 NULL, NULL, NULL, PRE_KERNEL_1,
    		 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &entropy_cc3xx_rng_api);
    
    // To this:
    DEVICE_DT_DEFINE(CRYPTOCELL_NODE_ID, NULL,
    		 NULL, NULL, NULL, PRE_KERNEL_1,
    		 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &entropy_cc3xx_rng_api);
    		 
    // Made entropy_cc3xx_rng_init global function


    nrf/subsys/nrf_security/src/zephyr/psa_crypto_init.c
    // Removed this SYS_INIT call
    SYS_INIT(_psa_crypto_init, POST_KERNEL,
    	 CONFIG_KERNEL_INIT_PRIORITY_DEVICE);


    nrf/subsys/nrf_security/src/zephyr/mbedtls_heap.c
    // Removed this SYS_INIT call and made mbedtls_heap_init global function
    SYS_INIT(mbedtls_heap_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);


    This is my work in progress lazy init piece of code that I can run from main or from work_q...
    extern int hw_cc3xx_init(void);
    extern int entropy_cc3xx_rng_init(const struct device *dev);
    extern int mbedtls_heap_init(void);
    
    static int lazy_crypto_init(void)
    {
    	static bool lazy_crypto_done = false;
    
    	if (lazy_crypto_done) {
    		return 0;
    	}
    
    	LOG_INF("lazy start!!!!");
    	int res = hw_cc3xx_init();
    	LOG_INF("hw_cc3xx_init returned: %d", res);
    
    	if (res != 0) {
    		LOG_ERR("CC3XX init failed: %d", res);
    		return res;
    	}
    
    	const struct device *entropy_dev = DEVICE_DT_GET(DT_NODELABEL(cryptocell));
    	if (entropy_dev == NULL) {
    		LOG_ERR("ERROR: Entropy device is NULL!");
    		return -ENODEV;
    	}
    
    	res = entropy_cc3xx_rng_init(entropy_dev);
    	LOG_INF("entropy_cc3xx_rng_init returned: %d", res);
    
    	psa_status_t err = psa_crypto_init();
    
    	LOG_INF("psa_crypto_init returned: %d", err);
    	if (err != PSA_SUCCESS) {
    
    		LOG_ERR("psa_crypto_init failed: %d", err);
    	}
    
    	LOG_INF("mbedtls_heap_init");
    	mbedtls_heap_init();
    
    	lazy_crypto_done = true;
    	return res;
    }


    After this crypto lazy init I can setup BLE and run advertising. I've used PSA functions, I've did DFU over BLE.

    Do you see any possible downside here?

  • Thank you for the update. I was actually just looking into this when you posted this. hw_cc3xx_init_internal() initializes the RNG by calling nrf_cc3xx_platform_init(). While the zephyr,deferred-init property added to the cryptocell node correctly defers the entropy driver initialisation, it does not matter because the RNG is already being initialised by hw_cc3xx_init_internal(), which is not gated by this zephyr,deferred-init property that only applies to device drivers.

    I did the following in my test:

    1. Patched the hw_cc3xx.c file with this:

    diff --git a/drivers/hw_cc3xx/hw_cc3xx.c b/drivers/hw_cc3xx/hw_cc3xx.c
    index b4218477e4..88d34b772d 100644
    --- a/drivers/hw_cc3xx/hw_cc3xx.c
    +++ b/drivers/hw_cc3xx/hw_cc3xx.c
    @@ -25,13 +25,13 @@ static int hw_cc3xx_init_internal(void)
     	/* Initialize the cc3xx HW with or without RNG support */
     
     	/* Using same configurations as the users of entropy, see NCSDK-24914. */
    -#if CONFIG_ENTROPY_CC3XX || defined(CONFIG_PSA_NEED_CC3XX_CTR_DRBG_DRIVER)
    -	res = nrf_cc3xx_platform_init();
    -#elif defined(CONFIG_PSA_NEED_CC3XX_HMAC_DRBG_DRIVER)
    -	res = nrf_cc3xx_platform_init_hmac_drbg();
    -#else
    +//#if CONFIG_ENTROPY_CC3XX || defined(CONFIG_PSA_NEED_CC3XX_CTR_DRBG_DRIVER)
    +//	res = nrf_cc3xx_platform_init();
    +//#elif defined(CONFIG_PSA_NEED_CC3XX_HMAC_DRBG_DRIVER)
    +//	res = nrf_cc3xx_platform_init_hmac_drbg();
    +//#else
     	res = nrf_cc3xx_platform_init_no_rng();
    -#endif
    +//#endif
     
     	return res;
     }

    2. Then made sure to initialise the device before enabling bluetooth:

    const struct device *c312 = DEVICE_DT_GET(DT_NODELABEL(cryptocell));
    
    ...
    
        err = device_init(c312);
    	if (err) {
    		printk("Failed to initialize device: %s (err %s)", c312->name, err);
    	}

    I don't immediately see any problems with this approach but at a minimum you should check if there is anything else that tries to request entropy data on startup.

Related