diff --git a/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h b/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h index 8cf687c5b15dd2d27ddd65eb142bba8386992735..01577477e963747210b4f2e4c53a171d68c7d7b2 100644 --- a/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h +++ b/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h @@ -80,7 +80,30 @@ #define SE_CONFIG_DST(x) \ ((x) & ((0x7U) << SE_CONFIG_DST_SHIFT)) -/* DRNG random number generator config */ +/* DRBG random number generator config */ +#define SE_RNG_CONFIG_REG_OFFSET 0x340 + +#define DRBG_MODE_SHIFT 0 +#define DRBG_MODE_NORMAL \ + ((0UL) << DRBG_MODE_SHIFT) +#define DRBG_MODE_FORCE_INSTANTION \ + ((1UL) << DRBG_MODE_SHIFT) +#define DRBG_MODE_FORCE_RESEED \ + ((2UL) << DRBG_MODE_SHIFT) +#define SE_RNG_CONFIG_MODE(x) \ + ((x) & ((0x3UL) << DRBG_MODE_SHIFT)) + +#define DRBG_SRC_SHIFT 2 +#define DRBG_SRC_NONE \ + ((0UL) << DRBG_SRC_SHIFT) +#define DRBG_SRC_ENTROPY \ + ((1UL) << DRBG_SRC_SHIFT) +#define DRBG_SRC_LFSR \ + ((2UL) << DRBG_SRC_SHIFT) +#define SE_RNG_SRC_CONFIG_MODE(x) \ + ((x) & ((0x3UL) << DRBG_SRC_SHIFT)) + +/* DRBG random number generator entropy config */ #define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344U #define DRBG_RO_ENT_SRC_SHIFT 1 diff --git a/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c b/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c index 345b7d8e000ca22a8d85c6007438a3c6d6c04cdd..fa99db62084b757ffe895f6687b9fb269a93b3c5 100644 --- a/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c +++ b/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c @@ -114,15 +114,15 @@ static void tegra_se_make_data_coherent(const tegra_se_dev_t *se_dev) } /* - * Check for context save operation complete - * This function is invoked after the context save operation, + * Check that SE operation has completed after kickoff + * This function is invoked after an SE operation has been started, * and it checks the following conditions: * 1. SE_INT_STATUS = SE_OP_DONE * 2. SE_STATUS = IDLE * 3. AHB bus data transfer complete. * 4. SE_ERR_STATUS is clean. */ -static int32_t tegra_se_context_save_complete(const tegra_se_dev_t *se_dev) +static int32_t tegra_se_operation_complete(const tegra_se_dev_t *se_dev) { uint32_t val = 0; int32_t ret = 0; @@ -218,15 +218,14 @@ static inline int32_t tegra_se_ctx_save_auto_enable(const tegra_se_dev_t *se_dev } /* - * SE atomic context save. At SC7 entry, SE driver triggers the - * hardware automatically performs the context save operation. + * Wait for SE engine to be idle and clear pending interrupts before + * starting the next SE operation. */ -static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev) +static int32_t tegra_se_operation_prepare(const tegra_se_dev_t *se_dev) { int32_t ret = 0; uint32_t val = 0; - uint32_t blk_count_limit = 0; - uint32_t block_count, timeout; + uint32_t timeout; /* Wait for previous operation to finish */ val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET); @@ -240,15 +239,31 @@ static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev) ret = -ETIMEDOUT; } - /* Clear any pending interrupts */ - if (ret == 0) { - val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET); - tegra_se_write_32(se_dev, SE_INT_STATUS_REG_OFFSET, val); + /* Clear any pending interrupts from previous operation */ + val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET); + tegra_se_write_32(se_dev, SE_INT_STATUS_REG_OFFSET, val); + return ret; +} + +/* + * SE atomic context save. At SC7 entry, SE driver triggers the + * hardware automatically performs the context save operation. + */ +static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev) +{ + int32_t ret = 0; + uint32_t val = 0; + uint32_t blk_count_limit = 0; + uint32_t block_count; + + /* Check that previous operation is finalized */ + ret = tegra_se_operation_prepare(se_dev); - /* Ensure HW atomic context save has been enabled - * This should have been done at boot time. - * SE_CTX_SAVE_AUTO.ENABLE == ENABLE - */ + /* Ensure HW atomic context save has been enabled + * This should have been done at boot time. + * SE_CTX_SAVE_AUTO.ENABLE == ENABLE + */ + if (ret == 0) { ret = tegra_se_ctx_save_auto_enable(se_dev); } @@ -290,7 +305,7 @@ static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev) tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_CTX_SAVE); - ret = tegra_se_context_save_complete(se_dev); + ret = tegra_se_operation_complete(se_dev); } /* Check that context has written the correct number of blocks */ @@ -306,6 +321,81 @@ static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev) return ret; } +/* + * Security engine primitive operations, including normal operation + * and the context save operation. + */ +static int tegra_se_perform_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes) +{ + uint32_t nblocks = nbytes / TEGRA_SE_AES_BLOCK_SIZE; + int ret = 0; + + assert(se_dev); + + /* Use device buffers for in and out */ + tegra_se_write_32(se_dev, SE_OUT_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->dst_ll_buf))); + tegra_se_write_32(se_dev, SE_IN_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->src_ll_buf))); + + /* Check that previous operation is finalized */ + ret = tegra_se_operation_prepare(se_dev); + if (ret != 0) { + goto op_error; + } + + /* Program SE operation size */ + if (nblocks) { + tegra_se_write_32(se_dev, SE_BLOCK_COUNT_REG_OFFSET, nblocks - 1); + } + + /* Make SE LL data coherent before the SE operation */ + tegra_se_make_data_coherent(se_dev); + + /* Start hardware operation */ + tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_START); + + /* Wait for operation to finish */ + ret = tegra_se_operation_complete(se_dev); + +op_error: + return ret; +} + +/* + * Security Engine sequence to generat SRK + * SE and SE2 will generate different SRK by different + * entropy seeds. + */ +static int tegra_se_generate_srk(const tegra_se_dev_t *se_dev) +{ + int ret = PSCI_E_INTERN_FAIL; + uint32_t val; + + /* Confgure the following hardware register settings: + * SE_CONFIG.DEC_ALG = NOP + * SE_CONFIG.ENC_ALG = RNG + * SE_CONFIG.DST = SRK + * SE_OPERATION.OP = START + * SE_CRYPTO_LAST_BLOCK = 0 + */ + se_dev->src_ll_buf->last_buff_num = 0; + se_dev->dst_ll_buf->last_buff_num = 0; + + /* Configure random number generator */ + val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_ENTROPY); + tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val); + + /* Configure output destination = SRK */ + val = (SE_CONFIG_ENC_ALG_RNG | + SE_CONFIG_DEC_ALG_NOP | + SE_CONFIG_DST_SRK); + tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val); + + /* Perform hardware operation */ + ret = tegra_se_perform_operation(se_dev, 0); + + return ret; +} + /* * Initialize the SE engine handle */ @@ -313,7 +403,9 @@ void tegra_se_init(void) { INFO("%s: start SE init\n", __func__); - /* TODO: Bug 1854340. Generate random SRK */ + /* Generate random SRK to initialize DRBG */ + tegra_se_generate_srk(&se_dev_1); + tegra_se_generate_srk(&se_dev_2); INFO("%s: SE init done\n", __func__); } @@ -397,7 +489,8 @@ static void tegra_se_warm_boot_resume(const tegra_se_dev_t *se_dev) __func__, se_dev->se_num); } - /* TODO: Bug 1854340. Set a random value to SRK */ + /* Set a random value to SRK to initialize DRBG */ + tegra_se_generate_srk(se_dev); } /*