Gaurav Kashyap <quic_gaurkash@xxxxxxxxxxx> writes: > This message was sent from outside of Texas Instruments. > Do not click links or open attachments unless you recognize the source of this email and know the content is safe. > > Now that HWKM support is added to ICE, extend the ICE > driver to support hardware wrapped keys programming coming > in from the storage controllers (ufs and emmc). This is > similar to standard keys where the call is forwarded to > Trustzone, however certain wrapped key and HWKM specific > actions has to be performed around the SCM calls. > > Derive software secret support is also added by forwarding the > call to the corresponding scm api. > > Signed-off-by: Gaurav Kashyap <quic_gaurkash@xxxxxxxxxxx> > Tested-by: Neil Armstrong <neil.armstrong@xxxxxxxxxx> > --- > drivers/soc/qcom/ice.c | 119 +++++++++++++++++++++++++++++++++++++---- > include/soc/qcom/ice.h | 4 ++ > 2 files changed, 112 insertions(+), 11 deletions(-) > > diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c > index c718e8153b23..c3b852269dca 100644 > --- a/drivers/soc/qcom/ice.c > +++ b/drivers/soc/qcom/ice.c > @@ -27,6 +27,8 @@ > #define QCOM_ICE_REG_BIST_STATUS 0x0070 > #define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000 > #define QCOM_ICE_REG_CONTROL 0x0 > +#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 0x4040 > + > /* QCOM ICE HWKM registers */ > #define QCOM_ICE_REG_HWKM_TZ_KM_CTL 0x1000 > #define QCOM_ICE_REG_HWKM_TZ_KM_STATUS 0x1004 > @@ -48,6 +50,8 @@ > #define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2 > #define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4 > > +#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET 0x80 > + > #define QCOM_ICE_HWKM_REG_OFFSET 0x8000 > #define HWKM_OFFSET(reg) ((reg) + QCOM_ICE_HWKM_REG_OFFSET) > > @@ -68,6 +72,16 @@ struct qcom_ice { > bool hwkm_init_complete; > }; > > +union crypto_cfg { > + __le32 regval; > + struct { > + u8 dusize; > + u8 capidx; > + u8 reserved; > + u8 cfge; > + }; > +}; > + > static bool qcom_ice_check_supported(struct qcom_ice *ice) > { > u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION); > @@ -273,6 +287,51 @@ int qcom_ice_suspend(struct qcom_ice *ice) > } > EXPORT_SYMBOL_GPL(qcom_ice_suspend); > > +/* > + * HW dictates the internal mapping between the ICE and HWKM slots, > + * which are different for different versions, make the translation > + * here. For v1 however, the translation is done in trustzone. > + */ > +static int translate_hwkm_slot(struct qcom_ice *ice, int slot) > +{ > + return (ice->hwkm_version == 1) ? slot : (slot * 2); > +} > + > +static int qcom_ice_program_wrapped_key(struct qcom_ice *ice, > + const struct blk_crypto_key *key, > + u8 data_unit_size, int slot) > +{ > + union crypto_cfg cfg; > + int hwkm_slot; > + int err; > + > + hwkm_slot = translate_hwkm_slot(ice, slot); > + > + memset(&cfg, 0, sizeof(cfg)); > + cfg.dusize = data_unit_size; > + cfg.capidx = QCOM_SCM_ICE_CIPHER_AES_256_XTS; > + cfg.cfge = 0x80; > + This is a clever use of union, writing from one member and reading from inactive member. I hope this a common practice in linux(being used in some other module already) or fits the standard of C or will give deterministic result on other compilers as well. Thanks. Regards, Kamlesh > + /* Clear CFGE */ > + qcom_ice_writel(ice, 0x0, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 + > + QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot); > + > + /* Call trustzone to program the wrapped key using hwkm */ > + err = qcom_scm_ice_set_key(hwkm_slot, key->raw, key->size, > + QCOM_SCM_ICE_CIPHER_AES_256_XTS, data_unit_size); > + if (err) { > + pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err, > + slot); > + return err; > + } > + > + /* Enable CFGE after programming key */ > + qcom_ice_writel(ice, cfg.regval, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 + > + QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot); > + > + return err; > +} > + > int qcom_ice_program_key(struct qcom_ice *ice, > u8 algorithm_id, u8 key_size, > const struct blk_crypto_key *bkey, > @@ -288,24 +347,39 @@ int qcom_ice_program_key(struct qcom_ice *ice, > > /* Only AES-256-XTS has been tested so far. */ > if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS || > - key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) { > + (key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256 && > + key_size != QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED)) { > dev_err_ratelimited(dev, > "Unhandled crypto capability; algorithm_id=%d, key_size=%d\n", > algorithm_id, key_size); > return -EINVAL; > } > > - memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE); > - > - /* The SCM call requires that the key words are encoded in big endian */ > - for (i = 0; i < ARRAY_SIZE(key.words); i++) > - __cpu_to_be32s(&key.words[i]); > + if (bkey->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) { > + /* It is expected that HWKM init has completed before programming wrapped keys */ > + if (!ice->use_hwkm || !ice->hwkm_init_complete) { > + dev_err_ratelimited(dev, "HWKM not currently used or initialized\n"); > + return -EINVAL; > + } > + err = qcom_ice_program_wrapped_key(ice, bkey, data_unit_size, > + slot); > + } else { > + if (bkey->size != QCOM_ICE_CRYPTO_KEY_SIZE_256) > + dev_err_ratelimited(dev, > + "Incorrect key size; bkey->size=%d\n", > + algorithm_id); > + return -EINVAL; > + memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE); > > - err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, > - QCOM_SCM_ICE_CIPHER_AES_256_XTS, > - data_unit_size); > + /* The SCM call requires that the key words are encoded in big endian */ > + for (i = 0; i < ARRAY_SIZE(key.words); i++) > + __cpu_to_be32s(&key.words[i]); > > - memzero_explicit(&key, sizeof(key)); > + err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE, > + QCOM_SCM_ICE_CIPHER_AES_256_XTS, > + data_unit_size); > + memzero_explicit(&key, sizeof(key)); > + } > > return err; > } > @@ -313,7 +387,21 @@ EXPORT_SYMBOL_GPL(qcom_ice_program_key); > > int qcom_ice_evict_key(struct qcom_ice *ice, int slot) > { > - return qcom_scm_ice_invalidate_key(slot); > + int hwkm_slot = slot; > + > + if (ice->use_hwkm) { > + hwkm_slot = translate_hwkm_slot(ice, slot); > + /* > + * Ignore calls to evict key when HWKM is supported and hwkm init > + * is not yet done. This is to avoid the clearing all slots call > + * during a storage reset when ICE is still in legacy mode. HWKM slave > + * in ICE takes care of zeroing out the keytable on reset. > + */ > + if (!ice->hwkm_init_complete) > + return 0; > + } > + > + return qcom_scm_ice_invalidate_key(hwkm_slot); > } > EXPORT_SYMBOL_GPL(qcom_ice_evict_key); > > @@ -323,6 +411,15 @@ bool qcom_ice_hwkm_supported(struct qcom_ice *ice) > } > EXPORT_SYMBOL_GPL(qcom_ice_hwkm_supported); > > +int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[], > + unsigned int wkey_size, > + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]) > +{ > + return qcom_scm_derive_sw_secret(wkey, wkey_size, > + sw_secret, BLK_CRYPTO_SW_SECRET_SIZE); > +} > +EXPORT_SYMBOL_GPL(qcom_ice_derive_sw_secret); > + > static struct qcom_ice *qcom_ice_create(struct device *dev, > void __iomem *base) > { > diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h > index 1f52e82e3e1c..dabe0d3a1fd0 100644 > --- a/include/soc/qcom/ice.h > +++ b/include/soc/qcom/ice.h > @@ -17,6 +17,7 @@ enum qcom_ice_crypto_key_size { > QCOM_ICE_CRYPTO_KEY_SIZE_192 = 0x2, > QCOM_ICE_CRYPTO_KEY_SIZE_256 = 0x3, > QCOM_ICE_CRYPTO_KEY_SIZE_512 = 0x4, > + QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED = 0x5, > }; > > enum qcom_ice_crypto_alg { > @@ -35,5 +36,8 @@ int qcom_ice_program_key(struct qcom_ice *ice, > u8 data_unit_size, int slot); > int qcom_ice_evict_key(struct qcom_ice *ice, int slot); > bool qcom_ice_hwkm_supported(struct qcom_ice *ice); > +int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[], > + unsigned int wkey_size, > + u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]); > struct qcom_ice *of_qcom_ice_get(struct device *dev); > #endif /* __QCOM_ICE_H__ */ > -- > 2.43.0