Tegra210B01: initialize DRBG on boot and resume

DRBG must be initialized to guarantee SRK has a random
value during suspend. This patch add a sequence to generate
an SRK on boot and during resume for SE1 and SE2. This SRK
value is not saved to PMC scratch, and should be overwitten
during atomic suspend.

Change-Id: Id5e2dc74a1b462dd6addaec1709fec46083a6e1c
Signed-off-by: Sam Payne <spayne@nvidia.com>
This commit is contained in:
Sam Payne 2017-05-15 11:10:37 -07:00 committed by Varun Wadekar
parent dd1a71f1c2
commit 8668fe0c80
2 changed files with 136 additions and 20 deletions

View File

@ -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

View File

@ -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;
}
/* Ensure HW atomic context save has been enabled
* This should have been done at boot time.
* SE_CTX_SAVE_AUTO.ENABLE == ENABLE
*/
/*
* 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
*/
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);
}
/*