CC3XX: Add a stateless API to read the TRNG
This stateless API can be used also in places where global
variables are not setup yet, i.e. in pre-main. The function
does not retain any state or config that might have changed
during its execution. It does not bypass HW tests.
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Change-Id: Ic7d4043c77b3dac6f21da87fc252d1210b0faaa7
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
index b9fb87e..1aca5b8 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/include/cc3xx_trng.h
@@ -57,7 +57,7 @@
void cc3xx_lowlevel_trng_sp800_90b_mode(bool enable);
/**
- * @brief Sets the configuration (ROSC_ID, subsampling rate) for
+ * @brief Sets the global configuration (ROSC_ID, subsampling rate) for
* the usage of the TRNG by the other APIs used by this
* module. If this is not called, default parameters
* defined at build time will be used, i.e.
@@ -75,7 +75,7 @@
cc3xx_err_t cc3xx_lowlevel_trng_set_config(enum cc3xx_rng_rosc_id_t rosc_id, uint32_t subsampling_rate);
/**
- * @brief Validates the configuration of the TRNG
+ * @brief Validates the global configuration of the TRNG
*
* @return cc3xx_err_t CC3XX_ERR_SUCCESS on success, or CC3XX_ERR_RNG_INVALID_TRNG_CONFIG if
* an invalid configuration is detected
@@ -84,7 +84,7 @@
/**
* @brief Sets the TRNG_DEBUG_CONTROL register to bypass mode for the
- * respective HW tests
+ * respective HW tests, in the global configuration (state) structure
*
* @param[in] bypass_autocorr Set to \a true to bypass the AUTOCORR test
* @param[in] bypass_crngt Set to \a true to bypass the CRNGT test
@@ -94,13 +94,39 @@
void cc3xx_lowlevel_trng_set_hw_test_bypass(bool bypass_autocorr, bool bypass_crngt, bool bypass_vnc);
/**
- * @brief Reads the sample out of the TRNG
+ * @brief Reads the sample out of the TRNG, without accessing the global config state
*
- * @param[out] buf Output buffer, word aligned, into which the entropy is read
+ * @param[out] buf Output buffer, word aligned, into which the sample is read
* @param[in] word_count Size in words of the \p buf output buffer, must be equal to
* the number of words of P_CC3XX->rng.ehr_data, i.e. CC3XX_TRNG_SAMPLE_SIZE
* when expressed in bytes
*
+ * @note If the ROSC ID or the subsampling rate get bumped during a reading, the new
+ * values won't be saved in the global config. This function does not access
+ * any global config or state so it is safe to use when globals are not set up.
+ * HW tests are not bypassed when this function is used
+ *
+ * @note This is a one-shot function, unlike the \a cc3xx_lowlevel_trng_get_sample
+ * which requires separate calls to \a cc3xx_lowlevel_trng_init first, and
+ * \a cc3xx_lowlevel_trng_finish afterwards
+ *
+ * @return cc3xx_err_t CC3XX_ERR_SUCCESS on success, CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS in
+ * case errors have been detected on each generation. The maximum
+ * number of generations is controlled by CC3XX_CONFIG_RNG_MAX_ATTEMPTS
+ */
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample_stateless(uint32_t *buf, size_t word_count);
+
+/**
+ * @brief Reads the sample out of the TRNG
+ *
+ * @param[out] buf Output buffer, word aligned, into which the sample is read
+ * @param[in] word_count Size in words of the \p buf output buffer, must be equal to
+ * the number of words of P_CC3XX->rng.ehr_data, i.e. CC3XX_TRNG_SAMPLE_SIZE
+ * when expressed in bytes
+ *
+ * @note This function might alter the global config (state) hence it requires global
+ * variables to be available
+ *
* @return cc3xx_err_t CC3XX_ERR_SUCCESS on success, CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS in
* case errors have been detected on each generation. The maximum
* number of generations is controlled by CC3XX_CONFIG_RNG_MAX_ATTEMPTS
@@ -108,7 +134,7 @@
cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count);
/**
- * @brief Initialises the TRNG before a call to \a cc3xx_lowlevel_trng_get_entropy
+ * @brief Initialises the TRNG before a call to \a cc3xx_lowlevel_trng_get_sample
*
* @return cc3xx_err_t CC3XX_ERR_SUCCESS
*/
diff --git a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
index 8766e06..9b22711 100644
--- a/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
+++ b/platform/ext/target/arm/drivers/cc3xx/low_level_driver/src/cc3xx_trng.c
@@ -100,47 +100,42 @@
P_CC3XX->rng.rng_clk_enable = 0x0U;
}
-static inline void trng_double_subsampling_rate(void)
+static inline uint32_t trng_double_subsampling_rate(uint32_t subsampling_rate)
{
- uint64_t product = (uint64_t)g_trng_config.rosc.subsampling_rate * 2ULL;
+ const uint64_t product = ((uint64_t)subsampling_rate) * 2ULL;
- g_trng_config.rosc.subsampling_rate =
- (product > UINT32_MAX) ? UINT32_MAX : (uint32_t)product;
+ return (product > UINT32_MAX) ? UINT32_MAX : (uint32_t)product;
}
-static void trng_bump_rosc_id_and_subsampling_rate(void)
+static void trng_bump_rosc_id_and_subsampling_rate(bool stateless)
{
- if (g_trng_config.rosc.id == CC3XX_RNG_ROSC_ID_3 &&
- g_trng_config.rosc.subsampling_rate == UINT32_MAX) {
+ uint32_t rosc_id = P_CC3XX->rng.trng_config & 0b11;
+ uint32_t rosc_subsampling_rate = P_CC3XX->rng.sample_cnt1;
+
+ if ((rosc_id == CC3XX_RNG_ROSC_ID_3) && (rosc_subsampling_rate == UINT32_MAX)) {
/* Cannot bump further */
return;
}
- if (g_trng_config.rosc.id < CC3XX_RNG_ROSC_ID_3) {
+ if (rosc_id < CC3XX_RNG_ROSC_ID_3) {
/* For each subsampling rate, bump the rosc id */
- g_trng_config.rosc.id++;
+ rosc_id++;
} else {
/* Double the subsampling rate when rosc id is at its max*/
- g_trng_config.rosc.id = CC3XX_RNG_ROSC_ID_0;
- trng_double_subsampling_rate();
+ rosc_id = CC3XX_RNG_ROSC_ID_0;
+ rosc_subsampling_rate = trng_double_subsampling_rate(rosc_subsampling_rate);
+ }
+
+ P_CC3XX->rng.trng_config = rosc_id | (0x1U << 2);
+ P_CC3XX->rng.sample_cnt1 = rosc_subsampling_rate;
+
+ if (!stateless) {
+ g_trng_config.rosc.id = rosc_id;
+ g_trng_config.rosc.subsampling_rate = rosc_subsampling_rate;
}
}
-cc3xx_err_t cc3xx_lowlevel_trng_init(void)
-{
- trng_init(g_trng_config.rosc.id, g_trng_config.rosc.subsampling_rate, g_trng_config.debug_control);
-
- return CC3XX_ERR_SUCCESS;
-}
-
-cc3xx_err_t cc3xx_lowlevel_trng_finish(void)
-{
- trng_finish();
-
- return CC3XX_ERR_SUCCESS;
-}
-
-cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count)
+static cc3xx_err_t trng_get_sample(uint32_t *buf, size_t word_count, bool stateless)
{
uint32_t attempt_count = 0;
uint32_t idx;
@@ -165,18 +160,21 @@
P_CC3XX->rng.rng_icr = 0x3FU;
/* Bump the rosc id and subsampling rate */
- trng_bump_rosc_id_and_subsampling_rate();
+ trng_bump_rosc_id_and_subsampling_rate(stateless);
/* Restart TRNG */
- cc3xx_lowlevel_trng_init();
+ trng_init(
+ P_CC3XX->rng.trng_config & 0b11,
+ P_CC3XX->rng.sample_cnt1,
+ P_CC3XX->rng.trng_debug_control);
attempt_count++;
}
- } while ((! (P_CC3XX->rng.rng_isr & 0x1U))
- && attempt_count < CC3XX_CONFIG_RNG_MAX_ATTEMPTS);
+ } while ((!(P_CC3XX->rng.rng_isr & 0x1U))
+ && (attempt_count < CC3XX_CONFIG_RNG_MAX_ATTEMPTS));
if (attempt_count == CC3XX_CONFIG_RNG_MAX_ATTEMPTS) {
- cc3xx_lowlevel_trng_finish();
+ trng_finish();
FATAL_ERR(CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS);
return CC3XX_ERR_RNG_TOO_MANY_ATTEMPTS;
}
@@ -197,6 +195,51 @@
return CC3XX_ERR_SUCCESS;
}
+/*!
+ * \defgroup cc3xx_trng Set of functions implementing the API to access the TRNG
+ * for reading random bits
+ *
+ */
+/*!@{*/
+cc3xx_err_t cc3xx_lowlevel_trng_init(void)
+{
+ trng_init(g_trng_config.rosc.id, g_trng_config.rosc.subsampling_rate, g_trng_config.debug_control);
+
+ return CC3XX_ERR_SUCCESS;
+}
+
+cc3xx_err_t cc3xx_lowlevel_trng_finish(void)
+{
+ trng_finish();
+
+ return CC3XX_ERR_SUCCESS;
+}
+
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample_stateless(uint32_t *buf, size_t word_count)
+{
+ cc3xx_err_t err;
+ const bool stateless = true;
+
+ /* In stateless mode do not set any TRNG test bypass */
+ trng_init(CC3XX_CONFIG_RNG_RING_OSCILLATOR_ID, CC3XX_CONFIG_RNG_SUBSAMPLING_RATE, 0x0);
+ err = trng_get_sample(buf, word_count, stateless);
+ if (err != CC3XX_ERR_SUCCESS) {
+ return err;
+ }
+ trng_finish();
+
+ return err;
+}
+
+cc3xx_err_t cc3xx_lowlevel_trng_get_sample(uint32_t *buf, size_t word_count)
+{
+ const bool stateless = false;
+ /* Unless called from the _stateless APIs, the get_sample will update
+ * the global config of the TRNG, i.e. to retain state for future calls
+ */
+ return trng_get_sample(buf, word_count, stateless);
+}
+
cc3xx_err_t cc3xx_lowlevel_trng_set_config(
enum cc3xx_rng_rosc_id_t rosc_id,
uint32_t subsampling_rate)
@@ -253,4 +296,5 @@
g_trng_config.debug_control = hw_entropy_tests_control;
}
+/*!@}*/
#endif /* !CC3XX_CONFIG_RNG_EXTERNAL_TRNG */